Integrations

Notification providers

Hermes supports sending notifications to 4 external providers. Each notification has configured in the database which providers should receive it. The platform dispatches asynchronously and independently to each enabled provider.

Provider

Type

Mechanism

Email

Email

JavaMailSender (SMTP)

Google Chat

Corporate messaging

Webhook HTTP

Slack

Team messaging

Webhook HTTP

Microsoft Teams

Corporate messaging

Power Automate Webhook


1. Configuration in application.yaml

1.1 Google Chat

YAML
anjana:
  messaging:
    google-chat:
      webhook-url: https://chat.googleapis.com/v1/spaces/XXXXXXXXX/messages?key=YYYYYYY&token=ZZZZZZZ

How to obtain the Webhook URL:

  1. Open the target Google Chat Space

  2. Click on the Space name → Apps & integrations

  3. Add webhooks → Assign a name → Save

  4. Copy the generated URL (includes key and token as query parameters)

1.2 Slack

YAML
anjana:
  messaging:
    slack:
      webhook-url: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXX

How to obtain the Webhook URL:

  1. Go to api.slack.com/appsCreate New App

  2. Incoming Webhooks → Enable → Add New Webhook to Workspace

  3. Select the target channel → Allow

  4. Copy the generated Webhook URL

1.3 Microsoft Teams

YAML
anjana:
  messaging:
    teams:
      webhook-url: https://TENANT.webhook.office.com/webhookb2/XXXXXXXX@YYYYYYYY/IncomingWebhook/ZZZZZZZZ/WWWWWWWW

Important note: Teams has deprecated Office 365 Connectors. It is mandatory to use Power Automate with the "Post to a channel when a webhook request is received" connector.

How to configure with Power Automate:

  1. In Teams, go to the target channel → ...Workflows

  2. Search for "Post to a channel when a webhook request is received"Add workflow

  3. Name the flow → Next → copy the generated webhook URL

1.4 Email (SMTP)

YAML
spring:
  mail:
    host: smtp.example.com
    port: 587
    username: notifications@example.com
    password: ${MAIL_PASSWORD}
    properties:
      mail.smtp.auth: true
      mail.smtp.starttls.enable: true
    from: notifications@anjanadata.com

1.5 HTTP Timeouts (all webhook providers)

YAML
anjana:
  messaging:
    connectTimeoutSeconds: 10   # Maximum time to establish connection
    readTimeoutSeconds: 30      # Maximum time waiting for response
    writeTimeoutSeconds: 10     # Maximum time sending the request

1.6 Full configuration example

YAML
anjana:
  messaging:
    connectTimeoutSeconds: 10
    readTimeoutSeconds: 30
    writeTimeoutSeconds: 10
    google-chat:
      webhook-url: https://chat.googleapis.com/v1/spaces/XXXXXXXXX/messages?key=YYYYYYY&token=ZZZZZZZ
    slack:
      webhook-url: https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXX
    teams:
      webhook-url: https://TENANT.webhook.office.com/webhookb2/XXXXXXXX/IncomingWebhook/ZZZZZZZZ
  

spring:
  mail:
    host: smtp.gmail.com
    port: 587
    username: notifications@anjanadata.com
    password: ${MAIL_PASSWORD}
    properties:
      mail.smtp.auth: true
      mail.smtp.starttls.enable: true
    mail:
    from: notifications@anjanadata.com

2. Database Configuration

The external_sending field of the hermes.notification table controls which providers receive each type of notification. It is a comma-separated list of values.

2.1 Possible values

Value

Provider

EMAIL

Email

SLACK

Slack

MICROSOFT_TEAMS

Microsoft Teams

GOOGLE_CHAT

Google Chat

2.2 Query current configuration

SQL
SELECT
    notification_code,
    subject,
    severity,
    external_sending
FROM hermes.notification
ORDER BY notification_code;
image-20260730-071809.png



3. Format of sent messages

Each provider receives the message in a specific format automatically generated by Hermes. The subject and body are resolved via the translation keys (translation_key) configured in each notification, in all languages active on the platform.

3.1 Google Chat

JSON
{
  "text": "Notification subject
Full notification body"
}

3.2 Slack

JSON
{
  "text": "**Notification subject**
Full notification body"
}

3.3 Microsoft Teams (Adaptive Card)

JSON
{
  "type": "message",
  "attachments": [{
    "contentType": "application/vnd.microsoft.card.adaptive",
    "content": {
      "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
      "type": "AdaptiveCard",
      "version": "1.2",
      "body": [
        { "type": "TextBlock", "text": "Notification subject", "weight": "Bolder" },
        { "type": "TextBlock", "text": "Notification body", "wrap": true }
      ]
    }
  }]
}

3.4 Email

HTML email sent to the recipients configured in the notification, with the body built in all languages active in the installation.


4. Asynchronous execution pools

Each provider uses its own thread pool so as not to block the main thread. They are configurable in application.yaml:

YAML
anjana:
  hermes:
    mail-pool:
      pool-size: 5
      core-pool-size: 2
      queue-capacity: 100
    slack-pool:
      pool-size: 3
      core-pool-size: 1
      queue-capacity: 50
    teams-pool:
      pool-size: 3
      core-pool-size: 1
      queue-capacity: 50
    google-chat-pool:
      pool-size: 3
      core-pool-size: 1
      queue-capacity: 50

Parameter

Description

pool-size

Maximum number of concurrent threads for that provider

core-pool-size

Threads always active (even if there are no messages)

queue-capacity

Messages queued before starting to reject


5. Sending flow

Workflow event (task created, assigned, completed...)
       ↓
NotificationService.dispatchToProviders()
       ↓
   For each provider configured in external_sending:
       ├── EMAIL           → EmailService        (mailPoolTaskExecutor)
       ├── SLACK           → SlackService        (slackPoolTaskExecutor)
       ├── MICROSOFT_TEAMS → TeamsService        (teamsPoolTaskExecutor)
       └── GOOGLE_CHAT     → GoogleChatService   (googleChatPoolTaskExecutor)
                                  ↓
                        POST webhook / SMTP send

The providers are invoked in parallel and asynchronously, so a failure in one provider does not block or affect the others.


6. Verification and troubleshooting

6.1 Verify connectivity with curl

Bash
# Google Chat
curl -X POST \
  "https://chat.googleapis.com/v1/spaces/XXXXXXXXX/messages?key=YYYYYYY&token=ZZZZZZZ" \
  -H "Content-Type: application/json" \
  -d '{"text": "Connectivity test from Anjana Data"}'

# Slack
curl -X POST https://hooks.slack.com/services/T00000000/B00000000/XXXX \
  -H "Content-Type: application/json" \
  -d '{"text": "Connectivity test from Anjana Data"}'

6.2 Relevant logs in Hermes

The services log errors at ERROR level when sending fails:

ERROR c.a.h.googlechat.service.GoogleChatService - Error sending message to Google Chat
ERROR c.a.h.slack.service.SlackService          - Error sending message to Slack
ERROR c.a.h.teams.service.TeamsService          - Error sending message to Teams
ERROR c.a.h.email.service.EmailService          - Error sending email notification

6.3 Common issues

Symptom

Probable cause

Solution

Messages are not arriving in Google Chat

Webhook URL expired or incorrect

Regenerate the webhook in the Google Chat Space

401 error in Slack

Token revoked

Recreate the app/webhook in Slack

Teams is not receiving messages

Office 365 Connectors connector deprecated

Migrate to Power Automate

Timeout on send

readTimeoutSeconds too low

Increase the value (recommended: 30s)

Field external_sending is NULL

Notification with no providers configured

Update it in the Administration Panel with the desired providers

Duplicate messages

Pool misconfigured with multiple workers

Check core-pool-size and queue-capacity


Product Team · Anjana Data