SMTP Email Configuration for Self-Hosted Services
Notes on wiring SMTP into self-hosted applications so password reset emails, alert notifications, and admin messages actually get delivered. Most of the time you don’t want to run a mail server yourself — use a transactional SMTP provider and point your apps at it.
SMTP Configuration Basics
Common SMTP Settings
| Parameter | Description | Example Values |
|---|---|---|
| Host | SMTP server address | smtp.gmail.com, smtp.example.com |
| Port | SMTP port | 25, 587 (STARTTLS), 465 (SSL) |
| Security | Encryption method | STARTTLS, SSL/TLS, None |
| Username | SMTP auth username | user@example.com |
| Password | SMTP auth password | App-specific or account password |
| From Address | Sender email | noreply@example.com |
Port Selection Guide
| Port | Protocol | Use Case | Security |
|---|---|---|---|
| 25 | SMTP | Server-to-server | Usually unencrypted |
| 587 | SMTP+STARTTLS | Modern standard | Encrypted after STARTTLS |
| 465 | SMTP+SSL | Legacy SSL | Encrypted from start |
| 2525 | SMTP | Alternative (ISP blocks 25) | Depends on configuration |
Bitwarden SMTP Configuration
Environment Variables
Location: ./bwdata/env/global.override.env
# Admin email
globalSettings__mail__replyToEmail=no-reply@example.com
# SMTP settings
globalSettings__mail__smtp__host=smtp.example.com
globalSettings__mail__smtp__port=587
globalSettings__mail__smtp__username=bitwarden@example.com
globalSettings__mail__smtp__password=smtp_password
# Use STARTTLS
globalSettings__mail__smtp__ssl=false
globalSettings__mail__smtp__startTls=true Config.yml Format
Location: ./bwdata/config.yml
mail:
replyToEmail: no-reply@example.com
smtp:
host: smtp.example.com
port: 587
ssl: false
startTls: true
username: bitwarden@example.com
password: smtp_password Vaultwarden SMTP Configuration
Environment Variables
# SMTP server
SMTP_HOST=smtp.example.com
SMTP_FROM=vaultwarden@example.com
SMTP_FROM_NAME=Vaultwarden
# Port and security
SMTP_PORT=587
SMTP_SECURITY=starttls # or 'force_tls' or 'off'
# Authentication
SMTP_USERNAME=vaultwarden@example.com
SMTP_PASSWORD=smtp_password
# Advanced options
SMTP_TIMEOUT=15
SMTP_AUTH_MECHANISM=Plain # or Login, Xoauth2 Docker Compose Integration
version: '3'
services:
vaultwarden:
image: vaultwarden/server:latest
environment:
- SMTP_HOST=smtp.example.com
- SMTP_FROM=vaultwarden@example.com
- SMTP_PORT=587
- SMTP_SECURITY=starttls
- SMTP_USERNAME=vaultwarden@example.com
- SMTP_PASSWORD=${SMTP_PASSWORD} # From .env file
volumes:
- ./vw-data:/data Provider-Specific Configurations
Gmail
Requirements:
- Enable 2-Factor Authentication
- Create App-Specific Password
Configuration:
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=your-email@gmail.com
SMTP_PASSWORD=your-app-specific-password Note: Gmail has sending limits (500/day for free accounts)
Office 365 / Microsoft 365
Configuration:
SMTP_HOST=smtp.office365.com
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=your-email@yourdomain.com
SMTP_PASSWORD=your-password Modern Auth (OAuth2):
- Requires application registration in Azure AD
- More secure than basic auth
- Basic auth being phased out
SendGrid
Configuration:
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=apikey
SMTP_PASSWORD=your-sendgrid-api-key Advantages:
- 100 emails/day free tier
- Better deliverability
- Detailed analytics
Amazon SES
Configuration:
SMTP_HOST=email-smtp.us-east-1.amazonaws.com
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=your-ses-smtp-username
SMTP_PASSWORD=your-ses-smtp-password Setup Steps:
- Verify domain or email in SES console
- Generate SMTP credentials
- Request production access (remove sandbox limits)
Mailgun
Configuration:
SMTP_HOST=smtp.mailgun.org
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=postmaster@your-domain.mailgun.org
SMTP_PASSWORD=your-mailgun-smtp-password Self-Hosted (Postfix/Dovecot)
Configuration:
SMTP_HOST=mail.example.com
SMTP_PORT=587
SMTP_SECURITY=starttls
SMTP_USERNAME=sender@example.com
SMTP_PASSWORD=your-password Requirements:
- Properly configured MX records
- SPF, DKIM, DMARC records
- Reverse DNS (PTR record)
- Not on spam blacklists
Testing SMTP Configuration
Manual Test with Telnet
# Connect to SMTP server
telnet smtp.example.com 587
# Expected response
220 smtp.example.com ESMTP
# Initiate STARTTLS
EHLO localhost
250-smtp.example.com
250-STARTTLS
250 AUTH PLAIN LOGIN
# Start TLS
STARTTLS
220 Ready to start TLS Test with OpenSSL
# For STARTTLS (port 587)
openssl s_client -starttls smtp -connect smtp.example.com:587
# For SSL (port 465)
openssl s_client -connect smtp.example.com:465 Test with swaks (SMTP Test Tool)
# Install swaks
sudo apt install swaks # Debian/Ubuntu
brew install swaks # macOS
# Test email
swaks --to recipient@example.com \
--from sender@example.com \
--server smtp.example.com:587 \
--auth LOGIN \
--auth-user sender@example.com \
--auth-password 'password' \
--tls Test from Application Container
Bitwarden:
docker exec -it bitwarden-api bash
telnet smtp.example.com 587 Vaultwarden:
docker exec -it vaultwarden sh
nc -zv smtp.example.com 587 Troubleshooting Common Issues
Authentication Failures
Symptoms: Login failed, authentication error
Causes:
- Incorrect username/password
- 2FA not configured (requires app password)
- App passwords not enabled
Solutions:
- Verify credentials
- Generate app-specific password
- Check for special characters in password (escape if needed)
Connection Timeouts
Symptoms: Cannot connect to SMTP server
Causes:
- Firewall blocking outbound SMTP
- ISP blocking port 25/587
- Incorrect hostname
Solutions:
- Check firewall rules:
sudo ufw status - Try alternative port (2525)
- Verify DNS resolution:
nslookup smtp.example.com - Test connectivity:
telnet smtp.example.com 587
TLS/SSL Errors
Symptoms: Certificate errors, TLS handshake failed
Causes:
- Self-signed certificates
- Expired certificates
- Wrong security mode
Solutions:
- Use
SMTP_SECURITY=offfor testing (not production) - Update CA certificates:
sudo update-ca-certificates - Match security mode to port (587=STARTTLS, 465=SSL)
Emails Going to Spam
Causes:
- Missing SPF/DKIM/DMARC records
- Shared IP with poor reputation
- Generic “noreply” addresses
Solutions:
- Configure SPF record:
v=spf1 include:_spf.google.com ~all - Enable DKIM signing
- Set up DMARC policy:
v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com - Use reputable SMTP provider
Rate Limiting
Symptoms: Some emails not delivered
Causes:
- Provider rate limits exceeded
- Too many recipients
Solutions:
- Reduce email frequency
- Upgrade to paid plan
- Implement email queuing
Security Best Practices
Securing SMTP Credentials
1. Use Environment Variables
# .env file
SMTP_PASSWORD=your-secure-password 2. Use Docker Secrets (Swarm)
services:
app:
environment:
SMTP_PASSWORD_FILE: /run/secrets/smtp_password
secrets:
- smtp_password
secrets:
smtp_password:
file: ./secrets/smtp_password.txt 3. Use Vault/Secrets Manager
- HashiCorp Vault
- AWS Secrets Manager
- Azure Key Vault
Email Security Headers
SPF (Sender Policy Framework):
v=spf1 ip4:192.0.2.0/24 include:_spf.google.com ~all DKIM (DomainKeys Identified Mail):
- Sign emails with private key
- Publish public key in DNS
DMARC (Domain-based Message Authentication):
v=DMARC1; p=quarantine; rua=mailto:reports@example.com; pct=100 Encryption Requirements
| Port | Encryption | Recommendation |
|---|---|---|
| 25 | None/STARTTLS | ❌ Avoid for user auth |
| 587 | STARTTLS | ✅ Recommended |
| 465 | SSL/TLS | ✅ Acceptable |
| 2525 | STARTTLS | ✅ If 587 blocked |
Monitoring Email Delivery
Log Monitoring
Vaultwarden logs:
docker logs vaultwarden 2>&1 | grep -i smtp
docker logs vaultwarden 2>&1 | grep -i email Bitwarden logs:
docker logs bitwarden-api | grep -i mail Delivery Status Notifications
Configure bounce handling:
# Set bounce email address
SMTP_FROM=noreply@example.com Monitor bounce email inbox for:
- Hard bounces (invalid addresses)
- Soft bounces (temporary failures)
- Spam complaints
Email Analytics
Track metrics:
- Delivery rate
- Open rate (if supported)
- Bounce rate
- Spam complaints
Tools:
- SendGrid Analytics
- Mailgun Statistics
- AWS SES Dashboard
Alternative Email Solutions
Relay Services
1. SMTP Relay (Internal)
# Configure Postfix as relay
SMTP_HOST=localhost
SMTP_PORT=25
SMTP_SECURITY=off 2. Cloud Relay
- Google Workspace SMTP Relay
- Office 365 Connector
- AWS SES SMTP Interface
API-Based Email
Instead of SMTP, use APIs:
- SendGrid API
- Mailgun API
- Amazon SES API
- Postmark API
Advantages:
- Better deliverability
- More features (templates, analytics)
- Easier troubleshooting
Related Documentation
- Bitwarden Self-Hosted Deployment - Bitwarden email configuration
- Vaultwarden Self-Hosted Deployment - Vaultwarden email setup
- Docker Compose Configuration for Password Managers - Container configuration