SMTP & Email Alerts
Send automated email notifications when entity values change.
Overview
ControlBird's SMTP & Email Alerts feature delivers automated email notifications whenever an entity's value changes. It uses the same controller / endpoint / mapper configuration model as the device-integration protocols: a controller manages the service, an endpoint describes the SMTP server connection, and one or more mappers watch specific entities and send mail when their value changes. Encryption is supported through STARTTLS and implicit TLS, message content is template-driven, and per-mapper cooldowns provide rate limiting to prevent email floods.
Use this feature to alert operators about critical conditions, notify teams about system events, or produce change reports, all without writing any code. An optional OAuth attribution mode can send each message from the email address of the signed-in user who made the change, which is useful for audit trails. SMTP is a write-only protocol: ControlBird only sends mail, it never reads a mailbox.
Prefer a guided tutorial?
New to this? Follow the SMTP Email Alerts walkthrough for a step-by-step tour, then come back here for the full reference.
Key Concepts
- Mapper pattern. When a watched entity's value changes, the watching
SmtpMappertriggers the controller to send an email. This is the same controller / endpoint / mapper layering used by the protocol integrations. - Three entity types. A
SmtpClientControllerruns the service, aSmtpClientEndpointdefines the server connection and sender identity, and eachSmtpMapperbinds one watched entity to a set of recipients and templates. - Template variables. Subject and body templates support
{{value}}(current entity value),{{entity_name}}(the watched entity's path), and{{timestamp}}(ISO 8601 time). - Rate limiting. A configurable cooldown sets the minimum time between emails for a single mapper.
- OAuth attribution. With
UseWriterEmailIfAvailableenabled, a change made by an OpenID Connect user can be sent from that user'sOAuthEmailaddress instead of the endpoint's default sender. - Header-injection safety. Subject lines are sanitized so template content can never inject extra mail headers.
Architecture
An email-alert integration is assembled from three layers of entities. The controller manages the service lifecycle, the endpoint carries the SMTP server connection and sender identity, and each mapper binds a watched entity to its recipients and message templates.
| Layer | Entity | Role |
|---|---|---|
| Controller | SmtpClientController | Manages the overall SMTP email notification service |
| Endpoint | SmtpClientEndpoint | SMTP server connection, credentials, and sender identity |
| Mapper | SmtpMapper | Watches an entity and sends templated mail when its value changes |
Entity Reference
SmtpClientController
Manages the overall SMTP email notification service, following the same controller layer used by the device-integration protocols.
| Field | Type | Purpose |
|---|---|---|
Name | String | Display name for the controller (e.g. EmailNotifications) |
Description | String | Optional documentation describing this controller's purpose |
Disabled | Bool | Set to true to disable all SMTP functionality without removing configuration |
EndpointConnectionMode | Choice | Controls how the endpoint connection is established across the deployment |
SmtpClientEndpoint
Defines the SMTP server connection details, credentials, and sender identity.
| Field | Type | Purpose |
|---|---|---|
Host | String | SMTP server hostname (e.g. smtp.gmail.com, smtp.office365.com) |
Port | Int | SMTP server port; typically 587 for STARTTLS, 465 for implicit TLS, 25 for plaintext |
Security | Choice | Encryption mode: None (plaintext), StartTls (default), or ImplicitTls |
Username | String | SMTP authentication username (optional if the server allows anonymous) |
Password | String | SMTP authentication password, or an app-specific password for services like Gmail |
FromAddress | String | Default sender email address used in all notifications |
FromName | String | Display name for the sender (optional; creates Name <email> format) |
TimeoutMs | Int | SMTP connection timeout in milliseconds (default 30000) |
UseWriterEmailIfAvailable | Bool | When true, sends from the OAuth user's email address instead of FromAddress if the writer has AuthMethod = OpenID Connect |
SmtpMapper
Watches an entity's value for changes and triggers SMTP notifications with customizable templates and recipients. The last three fields are runtime statistics updated after every send attempt and are read-only.
| Field | Type | Purpose |
|---|---|---|
TargetEntity | EntityReference | The entity whose value changes trigger email notifications |
Recipients | String | Comma-separated list of recipient email addresses (at least one required) |
CcRecipients | String | Comma-separated list of CC recipients (optional) |
SubjectTemplate | String | Email subject line with template variables {{value}}, {{entity_name}}, {{timestamp}} |
BodyTemplate | String | Email body content with the same template variables; supports plain text or HTML |
ContentFormat | Choice | Email body format: Text (plain text) or Html (HTML with text fallback) |
CooldownMs | Int | Rate limiting: minimum milliseconds between emails for this mapper (0 = no rate limit) |
TriggerMode | Choice | Trigger condition: OnChange (only when the value differs) or OnAnyWrite (on any write) |
EmailsSent | Int | Runtime counter: total emails successfully sent by this mapper (read-only) |
LastSentAt | Timestamp | Runtime field: when the last email was successfully sent (read-only) |
LastError | String | Runtime field: error message from the last failed send attempt (read-only) |
Template Variables
Subject and body templates accept the following placeholders, expanded at send time:
| Variable | Resolves to |
|---|---|
{{value}} | The current value of the watched entity |
{{entity_name}} | The watched entity's path |
{{timestamp}} | The current time in ISO 8601 format |
Content normalization
Subject lines have newlines removed to prevent header injection, and body line endings are normalized. When ContentFormat is Html, a plain-text alternative is generated automatically, so clients that cannot render HTML still receive readable text.
SMTP Server Configuration
Set the endpoint Host, Port, and Security to match your mail provider. The three security modes are None (plaintext), StartTls (upgrade the connection after connecting), and ImplicitTls (TLS from the first byte).
# Gmail
Host = smtp.gmail.com
Port = 587
Security = StartTls
Username = [email protected]
Password = your-app-password
FromAddress = [email protected]
# Microsoft 365
Host = smtp.office365.com
Port = 587
Security = StartTls
# Amazon SES
Host = email-smtp.us-east-1.amazonaws.com
Port = 465
Security = ImplicitTlsGmail requires App Passwords
When 2-factor authentication is enabled on a Google account, regular passwords fail with SMTP authentication errors. Generate an App Password in your Google Account settings and use it as the endpoint Password.
Message Templates
Mapper templates support plain text or HTML. The examples below use the template variables to embed the live value, the entity identifier, and the time of the change.
# Simple plain-text alert
Subject = Alert: {{entity_name}} changed
Body = Value changed to {{value}} at {{timestamp}}# HTML report (ContentFormat = Html)
Subject = ControlBird: {{entity_name}} Update
Body =
<h2>Value Update</h2>
<p>Entity: <strong>{{entity_name}}</strong></p>
<p>New Value: <code>{{value}}</code></p>
<p><small>{{timestamp}}</small></p>Recipients
Recipients and CcRecipients are comma-separated lists; surrounding whitespace is trimmed. At least one valid recipient is required for the mapper to send.
Recipients = [email protected], [email protected]Rate Limiting
Set CooldownMs to throttle a noisy mapper. Any email that would fall inside the cooldown window since the last send is skipped.
# Send at most one email per minute from this mapper
CooldownMs = 60000 # any change within 60s of the last send is skippedCooldown scope
Rate limiting applies per mapper only: multiple mappers send independently and do not respect each other's cooldowns. The cooldown resets when the service restarts.
OAuth Email Attribution
When UseWriterEmailIfAvailable is enabled on the endpoint, an email triggered by a user action can be sent from that user's address, which is useful for audit trails. All three of the following conditions must hold:
UseWriterEmailIfAvailable = trueon the endpoint.- The writer's
AuthMethodisOpenID Connect. - The writer has a non-empty
OAuthEmailfield.
Silent fallback
If the OAuth email lookup fails or the feature is disabled (for example a Native or LDAP user makes the change, or the OpenID Connect user has no OAuthEmail), the endpoint's default FromAddress is used instead, with no error raised.
Common Patterns
- Critical alerts. Watch an alarm or status entity with
TriggerMode = OnChangeand a short plain-text template so operators get immediate, low-noise notifications. - HTML status reports. Use
ContentFormat = Htmlwith a richly formatted body; the automatic plain-text alternative covers clients that cannot render HTML. - Throttled high-frequency signals. Pair a frequently changing source with
CooldownMsto cap the email rate while still surfacing the latest value. - Audited operator actions. Enable
UseWriterEmailIfAvailableso change notifications carry the originating OpenID Connect user's address. - Monitoring the service. Watch
EmailsSent,LastSentAt, andLastErroron each mapper to confirm delivery and catch failures.
Troubleshooting & Limitations
- Gmail authentication errors. Use an App Password when 2-factor authentication is enabled; a normal password will be rejected.
- Controller will not initialize.
FromAddressmust be a valid email format; an invalid value prevents controller initialization. - Mapper never sends. The
Recipientsfield cannot be empty: at least one comma-separated address is mandatory. Malformed addresses cause the entire send to fail. - OAuth From not applied. OAuth email only works for
OpenID Connectusers; Native and LDAP users cannot use it. If the conditions are not met the defaultFromAddressis used silently. - Header injection. Newlines in subject templates would allow header injection, so the service strips them from subjects automatically.
- No retries. The service does not retry failed sends. A failure is recorded in
LastErrorand the send is abandoned. - Write-only protocol. SMTP only sends mail. There is no inbound or receive path by design.
- Inspecting traffic. The service logs SMTP traffic (MAIL FROM, TO, SUBJECT, and error responses) for diagnosis.