Outbound Email Service
Relevant source files
The following files were used as context for generating this wiki page:
The Outbound Email Service is responsible for sending emails from the platform to external recipients. The system employs a hybrid architectural approach, where inbound email is handled by a self-hosted SMTP server, but all outbound mail is relayed through external, professional email services like Amazon SES or SendGrid. This strategy is designed to maximize email deliverability and reduce the risks associated with managing IP reputation.
The service is primarily used for two purposes: sending transactional emails (e.g., account verification, password resets) and allowing administrators to compose and send emails from the web interface.
Sources: blueprint.md, deployment_guide.md
Architecture Overview
The outbound email functionality is composed of three main parts: the frontend UI, the backend API, and an external SMTP relay service. The user interacts with a "Compose" modal in the web application, which sends the email data to a dedicated API endpoint. The API then uses the OutboundService to connect to a pre-configured external SMTP server and send the email.
This diagram illustrates the high-level architecture of the outbound email flow.
Configuration
The Outbound Email Service is configured via environment variables. Outbound functionality must be explicitly enabled.
| Variable | Description | Default Value | Required |
|---|---|---|---|
OUTBOUND_ENABLED | A boolean flag to enable or disable the outbound email feature. | false | No |
OUTBOUND_SMTP_HOST | The hostname of the external SMTP relay server. | - | Yes, if enabled |
OUTBOUND_SMTP_PORT | The port for the SMTP server. | 587 | No |
OUTBOUND_SMTP_USER | The username for SMTP authentication. | - | No |
OUTBOUND_SMTP_PASS | The password for SMTP authentication. | - | No |
OUTBOUND_SMTP_SECURE | Whether to use a secure (TLS) connection. Set to true for ports 465/587. | false | No |
MAIL_FROM_NAME | The "From" name displayed in emails sent by the system. | "TempMail Pro" | No |
MAIL_FROM_ADDRESS | The "From" email address used for system emails. | The from address provided in the call | No |
MAIL_DOMAIN | The domain used to generate the Message-ID header. | "localhost" | No |
Sources: services/api/src/services/outbound.ts:8-12, 47-49, deployment_guide.md
Example Configuration (Amazon SES)
The deployment guide provides a concrete example for configuring the service with Amazon SES.
OUTBOUND_ENABLED=true
OUTBOUND_SMTP_HOST=email-smtp.us-east-1.amazonaws.com
OUTBOUND_SMTP_PORT=587
OUTBOUND_SMTP_USER=YOUR_SES_SMTP_USER
OUTBOUND_SMTP_PASS=YOUR_SES_SMTP_PASS
OUTBOUND_SMTP_SECURE=true
Sources: deployment_guide.md
Backend Implementation (OutboundService)
The core logic resides in the OutboundService class, which acts as a wrapper around the nodemailer library.
Sources: services/api/src/services/outbound.ts, services/api/package.json
Class Structure
This diagram shows the structure of the OutboundService class.
Key Methods
constructor(): Initializes thenodemailertransporter by reading theOUTBOUND_SMTP_*environment variables. It conditionally adds authentication details only ifOUTBOUND_SMTP_USERandOUTBOUND_SMTP_PASSare provided.
Sources: services/api/src/services/outbound.ts:7-29sendEmail(...): The main method for sending emails. It throws an error ifOUTBOUND_SMTP_HOSTis not configured. It constructs the email payload, generates a uniqueMessage-ID, adds custom headers (X-Mailer,List-Unsubscribe), and sends it using the transporter.
Sources: services/api/src/services/outbound.ts:31-64- Transactional Email Methods: The service includes helper methods for sending specific transactional emails, such as
sendVerificationEmail,sendWelcomeEmail, andsendPasswordResetEmail. These methods use predefined email templates.
Sources: services/api/src/services/outbound.ts:69-106 verifyConnection(): A utility method to test the SMTP connection and configuration by callingtransporter.verify().
Sources: services/api/src/services/outbound.ts:111-119
API Endpoint
The frontend interacts with the backend via a single API endpoint to send composed emails.
- Endpoint:
POST /messages/outbound - Authentication: Required.
- Request Body: The request must be
multipart/form-data.
The following table describes the form data fields expected by the endpoint, as constructed by the ComposeModal component.
| Field | Type | Description |
|---|---|---|
from | string | The sender's email address, chosen from the user's available inboxes. |
to | string | The recipient's email address. |
subject | string | The subject line of the email. |
text | string | The plain text version of the email body. |
html | string | The HTML version of the email body. |
attachments | File[] | An array of files to be attached to the email. |
Sources: services/web/src/components/ComposeModal.tsx:35-46
Frontend Integration
Email composition and sending are handled by the ComposeModal React component, which is managed by the main Dashboard page.
Sending Flow
The following sequence diagram details the process from the user clicking "Send" to the email being sent.
ComposeModal.tsx
This component provides a full-featured UI for writing emails:
- A dropdown to select the
fromaddress from the user's verified inboxes. - Input fields for
toandsubject. - A rich text editor (
Editorcomponent) for the emailbody. - A file input for adding
attachments. - Upon submission, it constructs a
FormDataobject and sends it to thePOST /messages/outboundendpoint.
Sources: services/web/src/components/ComposeModal.tsx
Dashboard.tsx
The Dashboard component controls access to the outbound sending feature. It contains a canSendOutbound flag which is only true if OUTBOUND_ENABLED is configured and the logged-in user has the ADMIN role. This indicates that composing and sending emails is an administrative privilege.
// services/web/src/pages/Dashboard.tsx:55-58
const isAdmin = user?.role === "ADMIN";
// Check outgoing support
const outboundEnabled =
String(window.env?.OUTBOUND_ENABLED ?? import.meta.env.VITE_OUTBOUND_ENABLED ?? "false").toLowerCase() === "true";
const canSendOutbound = outboundEnabled && isAdmin;