Mail Add-on
Send transactional email from any agent with a single API call. Self-hosted SMTP delivery. Every message is a signed strand record — full audit trail, no cloud intermediary.
SAPIX_MAIL_ENABLED=trueWorks without SMTP configured — messages are stored as
queued for local testing.Enable
SAPIX_MAIL_ENABLED=true # SMTP delivery (optional — without this, messages are stored as "queued") SAPIX_MAIL_SMTP_HOST=smtp.example.com SAPIX_MAIL_SMTP_PORT=587 # default 587 (STARTTLS) [email protected] SAPIX_MAIL_SMTP_PASS=your-smtp-password # Sender identity [email protected] SAPIX_MAIL_FROM_NAME="Your Application" # default: SapixDB
Sending Email
const res = await fetch("http://localhost:7475/v1/mail/send", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
to: ["[email protected]"],
subject: "Your session is complete",
body: "The DBA Agent has finished the daily health check.",
html_body: "<p>The DBA Agent has finished the <strong>daily health check</strong>.</p>",
// from: "[email protected]", // optional — uses SAPIX_MAIL_FROM_ADDRESS by default
}),
});
const { id, status } = await res.json();
// status: "sent" | "failed" | "queued"
console.log(`Message ${id}: ${status}`);import httpx
async with httpx.AsyncClient() as client:
r = await client.post(
"http://localhost:7475/v1/mail/send",
headers={"Authorization": f"Bearer {api_key}"},
json={
"to": ["[email protected]"],
"subject": "⚠ Table bloat alert — users table at 78%",
"body": (
"The DBA Agent detected critical table bloat on the users table.\n"
"Auto-VACUUM has been scheduled for the next maintenance window."
),
},
)
print(r.json()) # {"id": "msg_...", "status": "sent"}Every call stores the message in the agent's graph meta before attempting delivery. If SMTP is unreachable, the status is set to failed but the message is retained and can be inspected via the API.
Integration with the Auth Add-on
When both SAPIX_AUTH_ENABLED=true and SAPIX_MAIL_ENABLED=true, magic link emails are sent automatically when a user requests POST /v1/auth/magic-link/send. No additional configuration required.
SMTP Configuration
The mail add-on uses STARTTLS (port 587). TLS certificates are verified against the system certificate store. Common SMTP providers:
| Provider | SAPIX_MAIL_SMTP_HOST | Port | Notes |
|---|---|---|---|
| Gmail | smtp.gmail.com | 587 | Use App Password, not account password |
| Mailgun | smtp.mailgun.org | 587 | Use SMTP credentials from Mailgun dashboard |
| Postmark | smtp.postmarkapp.com | 587 | Use API token as password |
| self-hosted Postfix | your-host.com | 587 | Ensure STARTTLS is configured |
| local test (MailHog) | localhost | 1025 | No auth, no TLS — dev only |
HTTP API Reference
| Method | Path | Description |
|---|---|---|
| POST | /v1/mail/send | Send an email |
| GET | /v1/mail/messages?limit=50 | List sent messages, newest first |
| GET | /v1/mail/messages/:id | Get a single message by ID |
POST /v1/mail/send — Request body
| Field | Type | Required | Description |
|---|---|---|---|
| to | string[] | Yes | Recipient email addresses |
| subject | string | Yes | Email subject line |
| body | string | Yes | Plain-text body |
| from | string | No | Override from address |
| html_body | string | No | HTML body (multipart/alternative if provided) |
Message status values
| Status | Meaning |
|---|---|
| sent | SMTP server accepted the message |
| failed | SMTP server rejected or connection failed |
| queued | SMTP not configured — message stored, not delivered |
Strand audit records
| Payload type | Trigger |
|---|---|
| mail/sent | Every send_email() call (recorded before SMTP attempt) |
PHI / HIPAA Note
Message bodies are stored in plain text in the agent's GraphIndex meta column family. If email bodies may contain PHI (patient names, diagnoses, identifiers), ensure:
- Access to the agent is restricted with
SAPIX_ROOT_KEYand scoped API keys. - The HIPAA add-on is enabled for blob and record encryption.
- Where possible, send a link to a protected record rather than embedding PHI in the email body directly.
Configuration
| Environment variable | Default | Description |
|---|---|---|
| SAPIX_MAIL_ENABLED | false | Enable the mail add-on |
| SAPIX_MAIL_SMTP_HOST | — | SMTP server hostname |
| SAPIX_MAIL_SMTP_PORT | 587 | SMTP port (STARTTLS) |
| SAPIX_MAIL_SMTP_USER | — | SMTP authentication username |
| SAPIX_MAIL_SMTP_PASS | — | SMTP authentication password |
| SAPIX_MAIL_FROM_ADDRESS | [email protected] | Default sender address |
| SAPIX_MAIL_FROM_NAME | SapixDB | Default sender display name |
Known Limitations
- No retry. Failed sends are recorded as
status: "failed"but not retried automatically. Re-send manually via the API. - No inbound email. Outbound only. Inbound SMTP is a planned future add-on.
- No attachments. Plain-text and HTML bodies only. Reference a blob hash to link files.
- STARTTLS only. Implicit TLS (port 465) is not yet supported.
- No DKIM. Configure DKIM at your MTA or DNS layer.
- Message storage is unbounded. Use the Policy Engine retention rules to clean up old messages.