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:
The email worker enabled (
NOTIFICATION_EMAIL_WORKER_ENABLED=true).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 | |
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 |
|
| Must be exactly |
Batch size |
|
| 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:
Microsoft Graph — selected when all four Graph settings are set.
Generic SMTP — selected when an SMTP host is set.
Azure Communication Services — selected when a connection string is set.
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 |
|
|
From display 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
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_NAMEEnv var | Default | Purpose |
|---|---|---|
|
| When |
| unset | Development only: redirect all outgoing email to this single address. Do not set in production. |
|
| Sender address (all providers except Graph). |
| 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.
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-SECRETEnv var | Required | Purpose |
|---|---|---|
| yes | Mailbox user id / UPN to send from. |
| yes | App registration client id. |
| yes | Azure AD tenant id. |
| 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.
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-PASSWORDEnv var | Default | Purpose |
|---|---|---|
| — | SMTP server host. Required to select SMTP. |
|
| SMTP server port. |
| provider default for port |
|
|
|
|
|
|
|
| unset | Auth username (optional; set with 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.
email:
azureCommunicationService:
connectionString: # -> EMAIL_AZURE_COMMUNICATION_SERVICE_CONNECTION (sensitive)
fromSecretProvider:
vault: <vault-name>
secretKey: COMMUNICATION-SERVICE-CONNECTIONEnv var | Required | Purpose |
|---|---|---|
| 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.
email:
sendGrid:
apiKey: # -> EMAIL_SEND_GRID_API_KEY (sensitive)
fromSecretProvider:
vault: <vault-name>
secretKey: SEND-GRID-API-KEYEnv var | Required | Purpose |
|---|---|---|
| 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 |
|
|
Permalink redirect base URL |
|
|
Notes:
Emails also carry a
List-Unsubscribeheader 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:
Worker disabled —
NOTIFICATION_EMAIL_WORKER_ENABLEDmust be exactlytrue.Email globally disabled —
EMAIL_DISABLED=trueskips all sends.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).
Recipient has no email — if the recipient's email address cannot be resolved, that email is skipped.
Recipient unsubscribed — informative emails are skipped for users who unsubscribed from that type.
Network egress — the deployment must be allowed to reach the chosen provider's endpoint (e.g.
api.sendgrid.comfor SendGrid, Microsoft Graph / Azure endpoints for Graph and ACS, or your SMTP host).Redirected mail (non-prod) — if
EMAIL_SEND_DEFAULT_EMAILis set, all mail goes to that single address instead of the real recipients.