Notifications

6 min read

This page explains how the notification service delivers email, which email providers are supported, and how to configure each one.

Overview

The notification service (part of the backend-service-configuration service) delivers notifications to users over two channels:

  • In-app — shown in the notification inbox inside the product.

  • Email — sent to the recipient's email address via a configurable email provider.

Delivery is asynchronous. When a notification is published, the service immediately persists it and returns; in-app notifications appear in the inbox right away, while emails are picked up and sent by a background worker shortly afterwards. This means email delivery does not block the action that triggered the notification, and email is retried automatically if a send fails.

To send email you need two things:

  1. The email worker enabled (NOTIFICATION_EMAIL_WORKER_ENABLED=true).

  2. Exactly one email provider (transport) configured.

Both are covered below.

Notification channels & types

Each notification type is delivered on one or more channels (IN_APP, EMAIL). The channel set is fixed per type — it is not chosen by the caller. Current types:

Type

Channels

Table assignees notified

Email

Table row assigned

In-app + Email

Table sheet run complete

In-app + Email

Conduct task complete

In-app + Email

All current types are informative (as opposed to critical), which means recipients can unsubscribe from them (see section 6).

Enabling email delivery

Email is delivered by a background worker that polls for pending emails and sends them in batches.

Setting

Env var

Default

Purpose

Worker enabled

NOTIFICATION_EMAIL_WORKER_ENABLED

false

Must be exactly true to send any email. If unset/false, emails are queued but never delivered.

Batch size

NOTIFICATION_EMAIL_BATCH_SIZE

20

Number of emails claimed and sent per poll cycle.

Behavior:

  • The worker polls roughly every 15 seconds.

  • Failed sends are retried with exponential backoff, up to 3 attempts, after which the email is marked failed.

  • Emails stuck mid-send (e.g. after a crash) are automatically requeued.

Enabling the worker alone does not send email — you must also configure a provider (Section 4/5). With no provider configured, sends are silently skipped.

Supported email providers

The service supports four email providers (transports). You configure the one you want to use; the service auto-selects a single transport at runtime based on which settings are present, in this priority order:

  1. Microsoft Graph — selected when all four Graph settings are set.

  2. Generic SMTP — selected when an SMTP host is set.

  3. Azure Communication Services — selected when a connection string is set.

  4. SendGrid — the default fallback when none of the above are configured.

If settings for more than one provider are present, the highest-priority one in the list above wins.

Provider

Best for

Selection trigger

Microsoft Graph

Sending through a Microsoft 365 / Exchange Online mailbox using an Azure AD app registration.

All four Graph settings present.

Generic SMTP

Any standard SMTP server (your own mail relay, a third-party SMTP provider, etc.).

SMTP host present.

Azure Communication Services (ACS)

Sending via Azure Communication Services Email.

Connection string present.

SendGrid

Twilio SendGrid API. Default if nothing else is configured.

API key present (fallback).

Sender identity (used by SMTP, ACS, and SendGrid — Microsoft Graph sends from the configured mailbox):

Setting

Env var

Default

From address

EMAIL_SEND_GRID_FROM_EMAIL

no-reply@unique.app

From display name

EMAIL_SEND_GRID_FROM_NAME

falls back to the from address

Naming note: the EMAIL_SEND_GRID_FROM_* variables are historical — they set the sender identity for all providers, not only SendGrid.

Configuration reference

Configuration is normally set through the service's Helm chart email: block, which renders to the flat EMAIL_* environment variables the service reads. Secrets must be supplied via a secret provider (e.g. Azure Key Vault) rather than as plaintext. Each provider is shown below in both forms.

Shared / global settings

yaml
email:
  disabled: false          # -> EMAIL_DISABLED; set true to short-circuit all sends (useful locally)
  from:
    email: no-reply@unique.app   # -> EMAIL_SEND_GRID_FROM_EMAIL
    name: unique.app             # -> EMAIL_SEND_GRID_FROM_NAME

Env var

Default

Purpose

EMAIL_DISABLED

false

When true, all email sends are skipped.

EMAIL_SEND_DEFAULT_EMAIL

unset

Development only: redirect all outgoing email to this single address. Do not set in production.

EMAIL_SEND_GRID_FROM_EMAIL

no-reply@unique.app

Sender address (all providers except Graph).

EMAIL_SEND_GRID_FROM_NAME

from address

Sender display name.

Provider 1 — Microsoft Graph

Sends via the Microsoft Graph sendMail API using an Azure AD app registration (client credentials). All four settings are required to select this transport.

yaml
email:
  microsoftGraph:
    senderMailboxId: ''      # -> EMAIL_MICROSOFT_GRAPH_SENDER_MAILBOX_ID; mailbox user id / UPN to send from
    appClientId: ''          # -> EMAIL_MICROSOFT_GRAPH_APP_CLIENT_ID; app registration client id
    tenantId: ''             # -> EMAIL_MICROSOFT_GRAPH_TENANT_ID; Azure AD tenant id
    appClientSecret:         # -> EMAIL_MICROSOFT_GRAPH_APP_CLIENT_SECRET (sensitive)
      fromSecretProvider:
        vault: <vault-name>
        secretKey: EMAIL-MICROSOFT-GRAPH-APP-CLIENT-SECRET

Env var

Required

Purpose

EMAIL_MICROSOFT_GRAPH_SENDER_MAILBOX_ID

yes

Mailbox user id / UPN to send from.

EMAIL_MICROSOFT_GRAPH_APP_CLIENT_ID

yes

App registration client id.

EMAIL_MICROSOFT_GRAPH_TENANT_ID

yes

Azure AD tenant id.

EMAIL_MICROSOFT_GRAPH_APP_CLIENT_SECRET

yes

App client secret (store as a secret).

The app registration needs permission to send mail as the configured mailbox (e.g. the Mail.Send application permission).

Provider 2 — Generic SMTP

Sends through any standard SMTP server. Selected when a host is set.

yaml
email:
  genericSmtp:
    host: ''                 # -> EMAIL_GENERIC_SMTP_HOST
    port: 465                # -> EMAIL_GENERIC_SMTP_PORT
    secure: false            # -> EMAIL_GENERIC_SMTP_SECURE
    ignoreTls: false         # -> EMAIL_GENERIC_SMTP_IGNORE_TLS
    rejectUnauthorized: true # -> EMAIL_GENERIC_SMTP_REJECT_UNAUTHORIZED
    user: ''                 # -> EMAIL_GENERIC_SMTP_USER
    password:                # -> EMAIL_GENERIC_SMTP_PASSWORD (sensitive)
      fromSecretProvider:
        vault: <vault-name>
        secretKey: GENERIC-SMTP-PASSWORD

Env var

Default

Purpose

EMAIL_GENERIC_SMTP_HOST

SMTP server host. Required to select SMTP.

EMAIL_GENERIC_SMTP_PORT

465

SMTP server port.

EMAIL_GENERIC_SMTP_SECURE

provider default for port

true to use TLS from connection start (typical for port 465).

EMAIL_GENERIC_SMTP_IGNORE_TLS

false

true to disable STARTTLS negotiation.

EMAIL_GENERIC_SMTP_REJECT_UNAUTHORIZED

true

false to accept self-signed / untrusted server certificates (not recommended).

EMAIL_GENERIC_SMTP_USER

unset

Auth username (optional; set with password).

EMAIL_GENERIC_SMTP_PASSWORD

unset

Auth password (store as a secret).

Provider 3 — Azure Communication Services (ACS)

Sends via Azure Communication Services Email. Selected when a connection string is set.

yaml
email:
  azureCommunicationService:
    connectionString:        # -> EMAIL_AZURE_COMMUNICATION_SERVICE_CONNECTION (sensitive)
      fromSecretProvider:
        vault: <vault-name>
        secretKey: COMMUNICATION-SERVICE-CONNECTION

Env var

Required

Purpose

EMAIL_AZURE_COMMUNICATION_SERVICE_CONNECTION

yes

ACS connection string (store as a secret).

The sender address (EMAIL_SEND_GRID_FROM_EMAIL) must be a domain verified in your Azure Communication Services resource.

Provider 4 — SendGrid (default fallback)

Sends via the Twilio SendGrid API. Used when no other provider is configured.

yaml
email:
  sendGrid:
    apiKey:                  # -> EMAIL_SEND_GRID_API_KEY (sensitive)
      fromSecretProvider:
        vault: <vault-name>
        secretKey: SEND-GRID-API-KEY

Env var

Required

Purpose

EMAIL_SEND_GRID_API_KEY

yes

SendGrid API key (store as a secret). If missing, email sends are skipped.

The sender address should be a verified sender / authenticated domain in your SendGrid account.

Unsubscribe & permalinks

Informative emails include an unsubscribe link, and email call-to-action links use stable permalinks. Both point at the chat application front end (not directly at the notification service).

Setting

Env var

Example

Unsubscribe landing page base URL

NOTIFICATION_UNSUBSCRIBE_BASE_URL

https://<your-domain>/chat/notifications/unsubscribe

Permalink redirect base URL

NOTIFICATION_PERMALINK_BASE_URL

https://<your-domain>/chat/notifications/go

Notes:

  • Emails also carry a List-Unsubscribe header pointing at the unsubscribe URL, so mail clients can surface a native unsubscribe control.

  • Unsubscribe is scoped per notification type per user — unsubscribing from one type does not silence the others.

  • If these base URLs are not configured, unsubscribe links / permalinks are simply omitted from emails.

Branding & Theming

Emails are automatically branded per company using the company's configured theme — logo, colors, and product name are pulled from the theme. No email-specific branding configuration is required. If a company has no theme (or a value is missing), sensible defaults are used. Emails include a "Powered by Unique" footer.

Troubleshooting

If emails are not being delivered, check the following in order:

  1. Worker disabledNOTIFICATION_EMAIL_WORKER_ENABLED must be exactly true.

  2. Email globally disabledEMAIL_DISABLED=true skips all sends.

  3. No provider configured — with no provider settings present, the service falls back to SendGrid; if the SendGrid API key is also missing, sends are silently skipped. Configure one provider (Section 5).

  4. Recipient has no email — if the recipient's email address cannot be resolved, that email is skipped.

  5. Recipient unsubscribed — informative emails are skipped for users who unsubscribed from that type.

  6. Network egress — the deployment must be allowed to reach the chosen provider's endpoint (e.g. api.sendgrid.com for SendGrid, Microsoft Graph / Azure endpoints for Graph and ACS, or your SMTP host).

  7. Redirected mail (non-prod) — if EMAIL_SEND_DEFAULT_EMAIL is set, all mail goes to that single address instead of the real recipients.

Last updated