System Architecture
backend/internal/mailer/mailer.go:1-63backend/internal/mailer/smtp.go:1-103backend/internal/mailer/templates.go:11-20backend/internal/mailer/templates.go:21-36backend/internal/mailer/templates.go:35-36backend/internal/mailer/templates.go:37-37backend/internal/mailer/templates.go:83-88backend/internal/mailer/templates.go:89-93backend/internal/mailer/templates.go:98-124backend/internal/mailer/templates.go:165-168backend/internal/mailer/templates.go:179-180backend/internal/mailer/templates.go:181-192backend/internal/mailer/templates.go:197-287backend/internal/mailer/templates.go:382-396backend/internal/mailer/templates.go:400-414backend/internal/mailer/templates.go:419-438backend/internal/mailer/templates.go:445-473
System Architecture
Overview
tela's email system is a transactional email subsystem designed for reliability and flexibility, supporting both self-hosted and managed deployments. It provides a consistent, branded email experience across user actions like verification, password reset, and organization invites, while maintaining compatibility with email clients that force dark mode rendering.
Components
Mailer Interface
The mailer package defines a Mailer interface for sending transactional emails, with implementations for SMTP and logging. FromEnv() selects the appropriate driver based on environment variables, defaulting to a LogMailer if no SMTP host is configured. LogMailer prints emails to the server log, enabling development and first-boot flows without an email relay.
Sources: backend/internal/mailer/mailer.go:1-63
SMTP Driver
The smtpMailer implementation uses the go-mail library to send emails via an SMTP relay. It supports TLS options (starttls, ssl, none), authentication, and connection pooling via per-send dialing. It is provider-agnostic, allowing use with services like Resend, Postmark, SES, or self-hosted Postfix.
Sources: backend/internal/mailer/smtp.go:1-103
Email Templates
Emails are rendered using a Go template engine, with a consistent light-themed design optimized for email client compatibility. The emailView struct holds all data required for rendering, including branding, content, and CTAs. Templates are styled with inline CSS, using a fixed color palette for consistent rendering.
Sources: backend/internal/mailer/templates.go:11-20, backend/internal/mailer/templates.go:21-36, backend/internal/mailer/templates.go:98-124, backend/internal/mailer/templates.go:197-287
Branding and Customization
Email branding is handled via the Brand struct, which allows customization of the product name, logo, and accent color. A zero Brand results in the default "tela" branding. The applyBrand method white-labels the email view, applying the brand only when an organization name is provided.
Sources: backend/internal/mailer/templates.go:83-88, backend/internal/mailer/templates.go:165-168, backend/internal/mailer/templates.go:181-192
Email Content Types
Emails are structured into transactional and notification types. Transactional emails (e.g., password reset, verification) are sent for user actions, while notification emails are sent for user interactions (e.g., mentions). Templates support optional fields like snippets, diffs, and related links.
Sources: backend/internal/mailer/templates.go:59-63, backend/internal/mailer/templates.go:382-396, backend/internal/mailer/templates.go:400-414, backend/internal/mailer/templates.go:419-438, backend/internal/mailer/templates.go:445-473
Control and Data Flow
- A user action triggers an email send (e.g.,
VerifyEmail,ResetPassword). - A
Messageis constructed withHTMLandTextcontent, and optionally markedImportant. - The
Mailerinterface is used to send the message. - If SMTP is configured,
smtpMailer.Send()is called, creating a new client and sending via SMTP. - If SMTP is not configured,
LogMailer.Send()logs the email instead. - Email content is rendered using
renderHTMLandrenderText, applying branding and templates.
graph TD
A["User Action"] --> B["Mailer.Send()"]
B --> C["LogMailer.Send()"]
B --> D["smtpMailer.Send()"]
C --> E["Log Email"]
D --> F["Create SMTP Client"]
F --> G["Send Email via SMTP"]
G --> H["Email Delivered"]
H --> I["User Receives Email"]
B --> J["Render HTML/Text"]
J --> K["Apply Branding"]
K --> L["Finalize Template"]
L --> M["HTML Body"]
M --> N["Text Body"]
N --> O["Send Message"]
Why This Design?
The design prioritizes reliability and configurability. By supporting both SMTP and logging, tela can be used in environments without an email relay, such as local development or first-time self-hosting. The use of inline CSS ensures consistent rendering across email clients, which often force dark mode rendering that would break a dark-themed email.
Sources: backend/internal/mailer/mailer.go:1-63, backend/internal/mailer/templates.go:11-20, backend/internal/mailer/templates.go:83-88, backend/internal/mailer/templates.go:165-168, backend/internal/mailer/templates.go:181-192