Outbound Email (SMTP)
TruePPM sends outbound email — @mention notifications and the own-task notifications (a task assigned to you, the planned date of your task changing, a comment on your task) — through Django’s email backend. Delivery is best-effort and opt-in: a notification is emailed only when the recipient has turned the Email channel on for that event under User → Settings → Notifications. Email is off by default.
There is no in-app SMTP credential editor in the community edition. Transport is
configured through Django’s standard EMAIL_* settings, and the read-only
Workspace → Settings → Email & SMTP page reflects whatever the deployment is
configured with.
Configuration
Section titled “Configuration”TruePPM uses Django’s standard EMAIL_* settings. The Beat-driven drain runs on
the api, celery, and celery-beat workloads, so all three need the same
transport configuration.
| Setting | Purpose |
|---|---|
EMAIL_HOST | SMTP relay hostname. Unconfigured ⇒ “Not configured” on the status page. |
EMAIL_PORT | SMTP port (e.g. 587). |
EMAIL_USE_TLS | Use STARTTLS. |
EMAIL_USE_SSL | Use implicit SSL/TLS (mutually exclusive with TLS). |
EMAIL_HOST_USER | SMTP username. Never exposed by the API. |
EMAIL_HOST_PASSWORD | SMTP password. Never exposed by the API, never logged. |
DEFAULT_FROM_EMAIL | From address on every message (e.g. notify@example.com). |
EMAIL_BACKEND | Django backend; use the SMTP backend in production. |
Source EMAIL_HOST_PASSWORD from a secret manager that your settings override
reads — never commit it in plain text.
SPF, DKIM, and DMARC alignment
Section titled “SPF, DKIM, and DMARC alignment”DEFAULT_FROM_EMAIL is the domain receiving mail servers check SPF, DKIM,
and DMARC alignment against. TruePPM sends the mail; your DNS
configuration is what makes it trusted:
- Use a
DEFAULT_FROM_EMAILdomain you control and have publishedSPFandDKIMDNS records for. Most self-hosters send through a relay (Amazon SES, SendGrid, Postmark, or their own mail server viaEMAIL_HOST) — the relay’s setup docs walk through adding the requiredSPF(TXT) andDKIM(CNAME/TXT) records at your registrar or DNS host. DMARCalignment requires theFromdomain (DEFAULT_FROM_EMAIL) to match either theSPF-authenticated domain or theDKIM-signing domain. If your relay signs with a different domain thanDEFAULT_FROM_EMAIL, alignment fails even though the message was accepted and delivered by the relay.- A relay reporting “sent successfully” only confirms SMTP accepted the
message — it says nothing about
SPF/DKIM/DMARCalignment at the receiving end. Misaligned records are the most common reason self-hosted notification email lands in spam even though delivery looked fine from the sending side.
TruePPM has no setting that can enforce or verify this for you — SPF,
DKIM, and DMARC are DNS records you own and publish, not something a
.env value or Helm value configures.
Read-only status page
Section titled “Read-only status page”Workspace → Settings → Email & SMTP (workspace Admins and Owners only) shows the resolved transport mode, host, port, TLS/SSL, and From address. It never displays the username or password and cannot change configuration — update the Django settings and redeploy to change transport. A writable in-app SMTP configuration surface is a planned follow-up, not part of the community edition today.
Delivery behavior
Section titled “Delivery behavior”- Email is queued as a notification row and sent by the
drain_notification_emailsBeat task (every 30 s), never inline — a broker or SMTP outage delays delivery but does not block the triggering action. - Each message is retried up to 3 times; after that the notification remains in the in-app inbox but stops attempting email.
- Bodies are plain text. A recipient with no email address is skipped (the in-app notification still appears).
- Bodies carry a direct deep-link to the affected task when
FRONTEND_BASE_URLis set (e.g. thetask.blockedemail links straight to the blocked task). Leave it empty and the email still renders — it just omits the link. - Comment/mention snippets embedded in the body are bounded and word-wrapped before sending, so a very long unbroken string (a pasted URL, log line, or base64 blob) can’t render as one unbounded line in the recipient’s mail client.
List-Unsubscribe headers
Section titled “List-Unsubscribe headers”Notification email carries List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click headers (RFC 8058), pointed at the recipient’s
User → Settings → Notifications page. Gmail, Outlook, and other large
mailbox providers weight the presence of these headers into their
bulk-sender spam heuristics, so including them helps delivery even at
TruePPM’s low, opt-in notification volume.
The headers link to the login-gated preferences page, not a no-auth one-click
unsubscribe endpoint — TruePPM issues no per-notification unsubscribe token,
so “one click” here means one click through to sign-in and preferences, not
an anonymous unsubscribe. The headers are only added when
FRONTEND_BASE_URL is configured, since a
bare relative path is not a valid header value; leave it unset and the email
still sends, just without them.
Disabling email
Section titled “Disabling email”Leave SMTP unconfigured to run without outbound email — in-app notifications keep working and the status page reports the transport as not configured.