Email Notifications (SMTP)

Overview

Accent CMS includes a built-in SMTP notification service that plugins and core features can use to send email. Typical use cases include contact form submissions, comment notifications, build reports, and health alerts.

The service is disabled by default. It is included in the Standard and Pro binaries; serving in production requires a Standard or Pro license.

Configuration

Add an smtp section to your config.yaml:

smtp:
  enabled: true
  host: smtp.example.com
  port: 587
  username: "your-smtp-user"
  password: ""                    # prefer env var (see below)
  from: "noreply@example.com"
  tls: starttls                   # starttls, implicit, or none
  rate_limit: 10                  # max emails per minute
SettingDefaultDescription
enabledfalseActivate the SMTP service
host(required)SMTP server hostname
port587SMTP server port
usernameAuthentication username
password""Authentication password (prefer env var)
from(required)Default sender address
tlsstarttlsTLS mode: starttls, implicit, or none
rate_limit10Maximum emails per minute

TLS Modes

ModePortDescription
starttls587Connect plain, upgrade to TLS. Default for most providers.
implicit465Connect directly over TLS. Older style, still used by some providers.
none1025No encryption. Only for local dev servers (Mailpit, MailHog). Do not use in production.

Password Security

Store the SMTP password in an environment variable rather than config.yaml:

export ACCENTCMS_SMTP_PASSWORD="your-smtp-password"
accent serve --config config.yaml

The environment variable takes priority over the password field in config. This keeps credentials out of version control.

How It Works

The SMTP service provides two interfaces:

For plugins: An internal HTTP endpoint at /_internal/smtp/send (localhost-only). WASM plugins POST a JSON body:

{
  "to": ["recipient@example.com"],
  "subject": "Contact form submission",
  "body_text": "Plain text version",
  "body_html": "<p>HTML version (optional)</p>"
}

Responses: 200 OK, 400 Bad Request, 429 Too Many Requests, 500 Internal Server Error, 503 Service Unavailable.

For core features: A Rust API (SmtpService::send()) used by built-in features like build reports and health alerts. No HTTP overhead.

Rate Limiting

The rate_limit setting caps the number of emails per minute (default: 10). When exceeded, the service returns HTTP 429 (Too Many Requests). The counter resets every 60 seconds.

This prevents accidental email floods from misconfigured plugins or form spam.

Edition Requirements

The SMTP service is compiled into the Standard and Pro binaries; serving in production requires a Standard or Pro license. When smtp.enabled is false (the default), no SMTP connections are made and no resources are consumed.

Supported SMTP Providers

Any standard SMTP server works:

ProviderHostPortNotes
Gmailsmtp.gmail.com587Requires App Password
SendGridsmtp.sendgrid.net587API key as password
Mailgunsmtp.mailgun.org587Domain-specific credentials
AWS SESemail-smtp.{region}.amazonaws.com587IAM SMTP credentials
Self-hosted (Postfix)localhost25No auth needed on loopback

Plugin Usage

Plugins that need to send email add 127.0.0.1 to their allowed_hosts in plugin.toml:

[plugin]
allowed_hosts = ["127.0.0.1"]

Then POST to /_internal/smtp/send using the plugin runtime’s HTTP host function. See the bundled contact-form example plugin.