MAIL - nself-org/cli GitHub Wiki
The Mail service in nself provides email sending and testing capabilities across all environments. In development, nself uses MailPit as a local email testing server that captures all outgoing emails for inspection without delivering them to real recipients. In staging and production, nself integrates with external SMTP providers such as SendGrid, Amazon SES, Postmark, and Mailgun for actual email delivery.
Mail is one of the 7 optional services in nself. For development email testing, enable it with MAILPIT_ENABLED=true in your .env file. For production, configure your SMTP provider credentials instead. The nself Auth service automatically uses the configured mail service for password resets, email verification, and other authentication-related emails.
- Email Capture - Intercepts all outgoing SMTP messages from your application
- Web Interface - Browser-based UI for viewing, searching, and inspecting emails
- HTML/Text Preview - Render HTML emails or view plain text and raw source
- Attachment Support - View and download email attachments
- Search and Filter - Search emails by sender, recipient, subject, or content
- API Access - RESTful API for programmatic email inspection in tests
- SMTP Relay - Acts as a standard SMTP server on port 1025
- No External Delivery - Emails never leave your local environment
- Real-time Updates - New emails appear instantly in the web UI
- Provider Agnostic - Works with any standard SMTP provider
- Template Support - HTML email templates for transactional messages
- Delivery Tracking - Monitor send status through provider dashboards
- Retry Logic - Automatic retry on temporary delivery failures
- Rate Limiting - Configurable send rate to respect provider limits
| Service | Integration | Purpose |
|---|---|---|
| Auth | SMTP relay | Password resets, email verification, MFA codes |
| Custom Services (CS_N) | SMTP connection | Application transactional emails |
| Functions | Event handler | Triggered email sending via serverless functions |
| Hasura | Event triggers | Database-driven email notifications |
Enable MailPit in your .env file:
# MailPit Configuration (Development)
MAILPIT_ENABLED=trueAll other settings have sensible defaults.
# Required
MAILPIT_ENABLED=true
# Version
MAILPIT_VERSION=latest # Docker image tag (default: latest)
# Port Configuration
MAILPIT_SMTP_PORT=1025 # SMTP port for sending (default: 1025)
MAILPIT_UI_PORT=8025 # Web UI port (default: 8025)
# Route Configuration
MAILPIT_ROUTE=mail # Creates mail.yourdomain.com
# SMTP Settings
MAILPIT_MAX_MESSAGES=500 # Maximum stored messages (default: 500)
MAILPIT_SMTP_AUTH_ACCEPT_ANY=true # Accept any SMTP credentials (default: true)
# UI Settings
MAILPIT_UI_AUTH_FILE= # Optional: htpasswd file for UI auth
MAILPIT_WEBROOT=/ # Web UI root path (default: /)For staging and production, configure an external SMTP provider:
# SMTP Provider Configuration
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASSWORD=your-sendgrid-api-key
[email protected]
SMTP_FROM_NAME=Your App Name
SMTP_SECURE=true # Use TLS (default: true)
SMTP_AUTH_METHOD=LOGIN # Options: LOGIN, PLAIN, CRAM-MD5SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASSWORD=SG.your-api-key-here
SMTP_SECURE=true
[email protected]SMTP_HOST=email-smtp.us-east-1.amazonaws.com
SMTP_PORT=587
SMTP_USER=your-ses-smtp-user
SMTP_PASSWORD=your-ses-smtp-password
SMTP_SECURE=true
[email protected]SMTP_HOST=smtp.postmarkapp.com
SMTP_PORT=587
SMTP_USER=your-server-token
SMTP_PASSWORD=your-server-token
SMTP_SECURE=true
[email protected]SMTP_HOST=smtp.mailgun.org
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=your-mailgun-password
SMTP_SECURE=true
[email protected]SMTP_HOST=mail.yourdomain.com
SMTP_PORT=587
SMTP_USER=your-username
SMTP_PASSWORD=your-password
SMTP_SECURE=true
[email protected]
SMTP_AUTH_METHOD=LOGINThe nself Auth service automatically uses the configured mail settings for authentication emails:
# Auth email settings (uses SMTP_* variables above)
AUTH_EMAIL_ENABLED=true
AUTH_EMAIL_SIGNIN_EMAIL_VERIFIED_REQUIRED=true
# Customize Auth email templates
AUTH_EMAIL_TEMPLATE_FETCH_URL=http://functions:3400/api/email-templates
# Password reset settings
AUTH_EMAIL_PASSWORD_RESET_ENABLED=true
AUTH_EMAIL_PASSWORD_RESET_REDIRECT_URL=https://yourapp.com/reset-password
# Email verification settings
AUTH_EMAIL_VERIFY_ENABLED=true
AUTH_EMAIL_VERIFY_REDIRECT_URL=https://yourapp.com/verify-emailLocal Development:
- URL:
https://mail.local.nself.org - No authentication required by default
Direct Access:
- URL:
http://localhost:8025
Within Docker Network (MailPit):
- Host:
mailpit - Port:
1025
From Host Machine (MailPit):
- Host:
localhost - Port:
1025
Mail is managed through the nself service email command group:
# Check mail service status
nself service email status
# View mail configuration
nself service email config
# Send a test email
nself service email test --to [email protected]
# View recent emails (MailPit only)
nself service email list
# Clear all captured emails (MailPit only)
nself service email clear
# Open MailPit web interface
nself service email open
# Verify SMTP connectivity (production)
nself service email verify# View mail service logs
nself logs mailpit
# Restart mail service
nself restart mailpit
# Check all service URLs
nself urlsimport nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST || 'mailpit',
port: parseInt(process.env.SMTP_PORT || '1025'),
secure: process.env.SMTP_SECURE === 'true',
auth: process.env.SMTP_USER ? {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASSWORD,
} : undefined,
});
await transporter.sendMail({
from: process.env.SMTP_FROM || '[email protected]',
to: '[email protected]',
subject: 'Welcome to the application',
html: '<h1>Welcome</h1><p>Your account has been created.</p>',
});import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import os
smtp_host = os.environ.get('SMTP_HOST', 'mailpit')
smtp_port = int(os.environ.get('SMTP_PORT', 1025))
msg = MIMEMultipart('alternative')
msg['Subject'] = 'Welcome to the application'
msg['From'] = os.environ.get('SMTP_FROM', '[email protected]')
msg['To'] = '[email protected]'
html = '<h1>Welcome</h1><p>Your account has been created.</p>'
msg.attach(MIMEText(html, 'html'))
with smtplib.SMTP(smtp_host, smtp_port) as server:
if os.environ.get('SMTP_SECURE') == 'true':
server.starttls()
if os.environ.get('SMTP_USER'):
server.login(os.environ['SMTP_USER'], os.environ['SMTP_PASSWORD'])
server.send_message(msg)import (
"net/smtp"
"os"
)
host := getEnvOrDefault("SMTP_HOST", "mailpit")
port := getEnvOrDefault("SMTP_PORT", "1025")
msg := []byte("From: [email protected]\r\n" +
"To: [email protected]\r\n" +
"Subject: Welcome\r\n" +
"Content-Type: text/html\r\n\r\n" +
"<h1>Welcome</h1><p>Your account has been created.</p>")
err := smtp.SendMail(
host+":"+port,
nil, // No auth for MailPit
"[email protected]",
[]string{"[email protected]"},
msg,
)MailPit exposes a REST API for automated testing:
# List all messages
curl http://localhost:8025/api/v1/messages
# Search messages
curl http://localhost:8025/api/v1/search?query=welcome
# Get a specific message
curl http://localhost:8025/api/v1/message/{id}
# Delete all messages
curl -X DELETE http://localhost:8025/api/v1/messagesimport { describe, it, expect } from 'vitest';
describe('Email sending', () => {
it('should send welcome email on registration', async () => {
// Trigger registration
await registerUser({ email: '[email protected]' });
// Wait briefly for email delivery
await new Promise(resolve => setTimeout(resolve, 1000));
// Check MailPit for the email
const response = await fetch('http://localhost:8025/api/v1/messages');
const data = await response.json();
const welcomeEmail = data.messages.find(
msg => msg.To[0].Address === '[email protected]'
);
expect(welcomeEmail).toBeDefined();
expect(welcomeEmail.Subject).toContain('Welcome');
});
});| Access Point | Address | Purpose |
|---|---|---|
| Web UI (Browser) | https://mail.local.nself.org |
MailPit inbox viewer |
| SMTP (Docker) | mailpit:1025 |
Service-to-service email sending |
| SMTP (Host) | localhost:1025 |
Local development access |
| Web UI (Host) | http://localhost:8025 |
Direct MailPit UI access |
| API (Host) | http://localhost:8025/api/v1/ |
MailPit REST API |
| Resource | Minimum | Recommended | Notes |
|---|---|---|---|
| CPU | 0.05 cores | 0.1 cores | Very lightweight |
| Memory | 50MB | 128MB | Increases with stored messages |
| Storage | 50MB | 200MB | Depends on message volume |
| Network | Minimal | Low | SMTP traffic only |
MailPit is one of the lightest services in the nself stack. Storage usage is bounded by the MAILPIT_MAX_MESSAGES setting.
# Check mail service health
nself health mailpit
# Docker health check (built into compose config)
# Uses: wget --spider http://localhost:8025/
# Interval: 15s
# Timeout: 5s
# Retries: 3
# Verify SMTP is accepting connections
nself exec mailpit nc -z localhost 1025For production SMTP providers, monitor delivery through the provider's dashboard:
| Provider | Dashboard URL |
|---|---|
| SendGrid | app.sendgrid.com |
| Amazon SES | AWS Console > SES |
| Postmark | account.postmarkapp.com |
| Mailgun | app.mailgun.com |
- MailPit is only accessible within the Docker network and on localhost
- No authentication required by default (development tool)
- Optionally protect the UI with htpasswd:
MAILPIT_UI_AUTH_FILE=/path/to/htpasswd - No emails are delivered externally
- Store SMTP credentials in
.secrets(never in.env.dev) - Use TLS for all SMTP connections (
SMTP_SECURE=true) - Verify sender domain with SPF, DKIM, and DMARC records
- Use dedicated API keys with minimal permissions
- Monitor for unusual sending patterns
- Set up bounce and complaint handling with your provider
- Sanitize all user-provided data before inserting into templates
- Never include sensitive data (passwords, tokens) in email bodies
- Use short-lived, one-time-use tokens for password reset links
- Set appropriate redirect URLs to prevent open redirect attacks
# Check MailPit logs
nself logs mailpit
# Verify MailPit is enabled
grep MAILPIT_ENABLED .env
# Check for port conflicts
lsof -i :1025
lsof -i :8025
# Run diagnostics
nself doctor# Verify your service is sending to the correct SMTP host
# Inside Docker: host=mailpit, port=1025
# From host: host=localhost, port=1025
# Check MailPit is receiving connections
nself logs mailpit --follow
# Send a test email
nself service email test --to [email protected]
# Verify SMTP connectivity from your service container
nself exec your-service nc -z mailpit 1025# Verify SMTP configuration
nself service email verify
# Test SMTP connectivity
nself service email test --to [email protected]
# Check Auth service logs for email errors
nself logs auth | grep -i email
# Common issues:
# - Incorrect SMTP credentials
# - Sender domain not verified with provider
# - Provider rate limits exceeded
# - TLS/SSL configuration mismatch# Verify Auth email configuration
grep AUTH_EMAIL .env
# Check Auth service logs
nself logs auth
# Ensure SMTP settings are correct
grep SMTP .env
# Verify MailPit is running (development)
nself status mailpit# Check nginx routing
nself urls
# Verify MailPit is running
nself status
# Test direct access
curl -s http://localhost:8025/
# Rebuild nginx configuration
nself build --force && nself restart nginxWhen deploying to staging or production, replace MailPit with your SMTP provider:
# Development .env.dev
MAILPIT_ENABLED=true
# Production .env.prod (overrides .env.dev)
MAILPIT_ENABLED=false
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASSWORD=your-api-key
[email protected]
SMTP_SECURE=trueThe nself Auth service and your custom services will automatically use the correct SMTP configuration based on the active environment file.
- Optional Services Overview - All optional services
- Services Overview - Complete service listing
- Auth Documentation - Authentication email configuration
- Environment Variables - Full configuration reference
- Custom Services - Sending emails from custom services
- Secrets Management - Storing SMTP credentials securely
- Troubleshooting - Common issues and solutions