🦉 A Go implementation of a mail development and testing tool, fully compatible with MailDev, providing better performance and richer features
OwlMail is an SMTP server and web interface for development and testing environments that captures and displays all sent emails. It's a Go implementation of MailDev with 100% API compatibility, while providing better performance, lower resource usage, and richer features.
- ✅ SMTP Server - Receives and stores all sent emails (default port 1025)
- ✅ Web Interface - View and manage emails through a browser (default port 1080)
- ✅ Email Persistence - Emails saved as
.emlfiles, supports loading from directory - ✅ Email Relay - Supports forwarding emails to real SMTP servers
- ✅ Auto Relay - Supports automatically forwarding all emails with rule filtering
- ✅ SMTP Authentication - Supports PLAIN/LOGIN authentication
- ✅ TLS/STARTTLS - Supports encrypted connections
- ✅ SMTPS - Supports direct TLS connection on port 465 (OwlMail exclusive)
- 🆕 Batch Operations - Batch delete, batch mark as read
- 🆕 Email Statistics - Get email statistics
- 🆕 Email Preview - Lightweight email preview API
- 🆕 Email Export - Export emails as ZIP files
- 🆕 Configuration Management API - Complete configuration management (GET/PUT/PATCH)
- 🆕 Powerful Search - Full-text search, date range filtering, sorting
- 🆕 Improved RESTful API - More standardized API design (
/api/v1/*)
- ✅ 100% MailDev API Compatible - All MailDev API endpoints are supported
- ✅ Environment Variables Fully Compatible - Prioritizes MailDev environment variables, no configuration changes needed
- ✅ Auto Relay Rules Compatible - JSON configuration file format fully compatible
- ⚡ Single Binary - Compiled as a single executable, no runtime required
- ⚡ Low Resource Usage - Go compiled, lower memory footprint
- ⚡ Fast Startup - Faster startup time
- ⚡ High Concurrency - Go goroutines, better concurrent performance
# Clone repository
git clone https://github.com/soulteary/owlmail.git
cd owlmail
# Build
go build -o owlmail ./cmd/owlmail
# Run
./owlmailgo install github.com/soulteary/owlmail/cmd/owlmail@latest
owlmail# Start with default configuration (SMTP: 1025, Web: 1080)
./owlmail
# Custom ports
./owlmail -smtp 1025 -web 1080
# Use environment variables
export MAILDEV_SMTP_PORT=1025
export MAILDEV_WEB_PORT=1080
./owlmailThe easiest way to use OwlMail is to pull the pre-built image from GitHub Container Registry:
# Pull the latest image
docker pull ghcr.io/soulteary/owlmail:latest
# Pull a specific version (using commit SHA)
docker pull ghcr.io/soulteary/owlmail:sha-49b5f35
# Run container
docker run -d \
-p 1025:1025 \
-p 1080:1080 \
--name owlmail \
ghcr.io/soulteary/owlmail:latestAvailable Tags:
latest- Latest stable releasesha-<commit>- Specific commit SHA (e.g.,sha-49b5f35)main- Latest from main branch
Multi-Architecture Support:
The image supports both linux/amd64 and linux/arm64 architectures. Docker will automatically pull the correct image for your platform.
View all available images: GitHub Packages
# Build image for current architecture
docker build -t owlmail .
# Run container
docker run -d \
-p 1025:1025 \
-p 1080:1080 \
--name owlmail \
owlmailFor aarch64 (ARM64) or other architectures, use Docker Buildx:
# Enable buildx (if not already enabled)
docker buildx create --use --name multiarch-builder
# Build for multiple architectures
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t owlmail:latest \
--load .
# Or build and push to registry
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t your-registry/owlmail:latest \
--push .
# Build for specific architecture (e.g., aarch64/arm64)
docker buildx build \
--platform linux/arm64 \
-t owlmail:latest \
--load .Note: The Dockerfile now supports multi-architecture builds using TARGETOS and TARGETARCH build arguments, which are automatically set by Docker Buildx.
| Argument | Environment Variable | Default | Description |
|---|---|---|---|
-smtp |
MAILDEV_SMTP_PORT / OWLMAIL_SMTP_PORT |
1025 | SMTP port |
-ip |
MAILDEV_IP / OWLMAIL_SMTP_HOST |
localhost | SMTP host |
-web |
MAILDEV_WEB_PORT / OWLMAIL_WEB_PORT |
1080 | Web API port |
-web-ip |
MAILDEV_WEB_IP / OWLMAIL_WEB_HOST |
localhost | Web API host |
-mail-directory |
MAILDEV_MAIL_DIRECTORY / OWLMAIL_MAIL_DIR |
- | Mail storage directory |
-web-user |
MAILDEV_WEB_USER / OWLMAIL_WEB_USER |
- | HTTP Basic Auth username |
-web-password |
MAILDEV_WEB_PASS / OWLMAIL_WEB_PASSWORD |
- | HTTP Basic Auth password |
-https |
MAILDEV_HTTPS / OWLMAIL_HTTPS_ENABLED |
false | Enable HTTPS |
-https-cert |
MAILDEV_HTTPS_CERT / OWLMAIL_HTTPS_CERT |
- | HTTPS certificate file |
-https-key |
MAILDEV_HTTPS_KEY / OWLMAIL_HTTPS_KEY |
- | HTTPS private key file |
-outgoing-host |
MAILDEV_OUTGOING_HOST / OWLMAIL_OUTGOING_HOST |
- | Outgoing SMTP host |
-outgoing-port |
MAILDEV_OUTGOING_PORT / OWLMAIL_OUTGOING_PORT |
587 | Outgoing SMTP port |
-outgoing-user |
MAILDEV_OUTGOING_USER / OWLMAIL_OUTGOING_USER |
- | Outgoing SMTP username |
-outgoing-pass |
MAILDEV_OUTGOING_PASS / OWLMAIL_OUTGOING_PASSWORD |
- | Outgoing SMTP password |
-outgoing-secure |
MAILDEV_OUTGOING_SECURE / OWLMAIL_OUTGOING_SECURE |
false | Outgoing SMTP TLS |
-auto-relay |
MAILDEV_AUTO_RELAY / OWLMAIL_AUTO_RELAY |
false | Enable auto relay |
-auto-relay-addr |
MAILDEV_AUTO_RELAY_ADDR / OWLMAIL_AUTO_RELAY_ADDR |
- | Auto relay address |
-auto-relay-rules |
MAILDEV_AUTO_RELAY_RULES / OWLMAIL_AUTO_RELAY_RULES |
- | Auto relay rules file |
-smtp-user |
MAILDEV_INCOMING_USER / OWLMAIL_SMTP_USER |
- | SMTP authentication username |
-smtp-password |
MAILDEV_INCOMING_PASS / OWLMAIL_SMTP_PASSWORD |
- | SMTP authentication password |
-tls |
MAILDEV_INCOMING_SECURE / OWLMAIL_TLS_ENABLED |
false | Enable SMTP TLS |
-tls-cert |
MAILDEV_INCOMING_CERT / OWLMAIL_TLS_CERT |
- | SMTP TLS certificate file |
-tls-key |
MAILDEV_INCOMING_KEY / OWLMAIL_TLS_KEY |
- | SMTP TLS private key file |
-log-level |
MAILDEV_VERBOSE / MAILDEV_SILENT / OWLMAIL_LOG_LEVEL |
normal | Log level |
-use-uuid-for-email-id |
OWLMAIL_USE_UUID_FOR_EMAIL_ID |
false | Use UUID for email IDs (default: 8-character random string) |
OwlMail fully supports MailDev environment variables, prioritizing MailDev environment variables, and falling back to OwlMail environment variables if not present. This means you can use MailDev's configuration directly without modification.
# Use MailDev environment variables directly (recommended)
export MAILDEV_SMTP_PORT=1025
export MAILDEV_WEB_PORT=1080
export MAILDEV_OUTGOING_HOST=smtp.gmail.com
./owlmail
# Or use OwlMail environment variables
export OWLMAIL_SMTP_PORT=1025
export OWLMAIL_WEB_PORT=1080
./owlmailOwlMail uses a standardized API response format:
Success Response:
{
"code": "EMAIL_DELETED",
"message": "Email deleted",
"data": { ... }
}Error Response:
{
"code": "EMAIL_NOT_FOUND",
"error": "EMAIL_NOT_FOUND",
"message": "Email not found"
}The code field contains standardized error/success codes that can be used for internationalization. The message field provides English text for backward compatibility.
OwlMail supports two email ID formats, and all API endpoints are compatible with both:
- 8-character random string: Default format, e.g.,
aB3dEfGh - UUID format: 36-character standard UUID, e.g.,
550e8400-e29b-41d4-a716-446655440000
When using the :id parameter in API requests, you can use either format. For example:
GET /email/aB3dEfGh- Using random string IDGET /email/550e8400-e29b-41d4-a716-446655440000- Using UUID ID
OwlMail is fully compatible with all MailDev API endpoints:
GET /email- Get all emails (supports pagination and filtering)- Query parameters:
limit(default: 50, max: 1000) - Number of emails to returnoffset(default: 0) - Number of emails to skipq- Full-text search queryfrom- Filter by sender email addressto- Filter by recipient email addressdateFrom- Filter by date from (YYYY-MM-DD format)dateTo- Filter by date to (YYYY-MM-DD format)read- Filter by read status (true/false)sortBy- Sort by field (time, subject)sortOrder- Sort order (asc, desc, default: desc)
- Example:
GET /email?limit=20&offset=0&q=test&sortBy=time&sortOrder=desc
- Query parameters:
GET /email/:id- Get single emailDELETE /email/:id- Delete single emailDELETE /email/all- Delete all emailsPATCH /email/read-all- Mark all emails as readPATCH /email/:id/read- Mark single email as read
GET /email/:id/html- Get email HTML contentGET /email/:id/attachment/:filename- Download attachmentGET /email/:id/download- Download raw .eml fileGET /email/:id/source- Get email raw source
POST /email/:id/relay- Relay email to configured SMTP serverPOST /email/:id/relay/:relayTo- Relay email to specific address
GET /config- Get configuration informationGET /healthz- Health checkGET /reloadMailsFromDirectory- Reload emails from directoryGET /socket.io- WebSocket connection (standard WebSocket, not Socket.IO)
GET /email/stats- Get email statisticsGET /email/preview- Get email preview (lightweight)
POST /email/batch/delete- Batch delete emailsPOST /email/batch/read- Batch mark as read
GET /email/export- Export emails as ZIP file
GET /config/outgoing- Get outgoing configurationPUT /config/outgoing- Update outgoing configurationPATCH /config/outgoing- Partially update outgoing configuration
OwlMail provides a more standardized RESTful API design:
GET /api/v1/emails- Get all emails (plural resource)- Query parameters: Same as
GET /email(limit, offset, q, from, to, dateFrom, dateTo, read, sortBy, sortOrder) - Example:
GET /api/v1/emails?limit=20&offset=0&q=test&sortBy=time&sortOrder=desc
- Query parameters: Same as
GET /api/v1/emails/:id- Get single emailDELETE /api/v1/emails/:id- Delete single emailDELETE /api/v1/emails- Delete all emailsDELETE /api/v1/emails/batch- Batch deletePATCH /api/v1/emails/read- Mark all emails as readPATCH /api/v1/emails/:id/read- Mark single email as readPATCH /api/v1/emails/batch/read- Batch mark as readGET /api/v1/emails/stats- Email statisticsGET /api/v1/emails/preview- Email previewGET /api/v1/emails/export- Export emailsPOST /api/v1/emails/reload- Reload emailsGET /api/v1/settings- Get all settingsGET /api/v1/settings/outgoing- Get outgoing configurationPUT /api/v1/settings/outgoing- Update outgoing configurationPATCH /api/v1/settings/outgoing- Partially update outgoing configurationGET /api/v1/health- Health checkGET /api/v1/ws- WebSocket connection
For detailed API documentation, see: API Refactoring Record
# Start OwlMail
./owlmail -smtp 1025 -web 1080
# Configure SMTP in your application
SMTP_HOST=localhost
SMTP_PORT=1025# Relay to Gmail SMTP
./owlmail \
-outgoing-host smtp.gmail.com \
-outgoing-port 587 \
-outgoing-user your-email@gmail.com \
-outgoing-pass your-password \
-outgoing-secure# Create auto relay rules file (relay-rules.json)
cat > relay-rules.json <<EOF
[
{ "allow": "*" },
{ "deny": "*@test.com" },
{ "allow": "ok@test.com" }
]
EOF
# Start auto relay
./owlmail \
-outgoing-host smtp.gmail.com \
-outgoing-port 587 \
-outgoing-user your-email@gmail.com \
-outgoing-pass your-password \
-auto-relay \
-auto-relay-rules relay-rules.json./owlmail \
-https \
-https-cert /path/to/cert.pem \
-https-key /path/to/key.pem \
-web 1080./owlmail \
-smtp-user admin \
-smtp-password secret \
-smtp 1025./owlmail \
-tls \
-tls-cert /path/to/cert.pem \
-tls-key /path/to/key.pem \
-smtp 1025Note: When TLS is enabled, OwlMail automatically starts an SMTPS server on port 465 in addition to the regular SMTP server. The SMTPS server uses direct TLS connection (no STARTTLS required). This is an OwlMail exclusive feature.
OwlMail supports two email ID formats:
- Default format: 8-character random string (e.g.,
aB3dEfGh) - UUID format: 36-character standard UUID (e.g.,
550e8400-e29b-41d4-a716-446655440000)
Using UUID format provides better uniqueness and traceability, especially useful for integration with external systems.
# Enable UUID using command line flag
./owlmail -use-uuid-for-email-id
# Enable UUID using environment variable
export OWLMAIL_USE_UUID_FOR_EMAIL_ID=true
./owlmail
# Use with other configurations
./owlmail \
-use-uuid-for-email-id \
-smtp 1025 \
-web 1080Notes:
- Default uses 8-character random string, compatible with MailDev behavior
- When UUID is enabled, all newly received emails will use UUID format IDs
- The API supports both ID formats, allowing normal query, delete, and operation of emails
- Existing email ID formats will not change; only new emails will use the new ID format
OwlMail is fully compatible with MailDev and can be used as a drop-in replacement:
OwlMail prioritizes MailDev environment variables, no configuration changes needed:
# MailDev configuration
export MAILDEV_SMTP_PORT=1025
export MAILDEV_WEB_PORT=1080
export MAILDEV_OUTGOING_HOST=smtp.gmail.com
# Use OwlMail directly (no need to change environment variables)
./owlmailAll MailDev API endpoints are supported, existing client code requires no changes:
# MailDev API
curl http://localhost:1080/email
# OwlMail fully compatible
curl http://localhost:1080/emailIf using WebSocket, you need to change from Socket.IO to standard WebSocket:
// MailDev (Socket.IO)
const socket = io('/socket.io');
socket.on('newMail', (email) => { /* ... */ });
// OwlMail (Standard WebSocket)
const ws = new WebSocket('ws://localhost:1080/socket.io');
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'new') { /* ... */ }
};For detailed migration guide, see: OwlMail × MailDev: Full Feature & API Comparison and Migration White Paper
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run tests for specific packages
go test ./internal/api/...
go test ./internal/mailserver/...OwlMail/
├── cmd/
│ └── owlmail/ # Main program entry
├── internal/
│ ├── api/ # Web API implementation
│ ├── common/ # Common utilities (logging, error handling)
│ ├── maildev/ # MailDev compatibility layer
│ ├── mailserver/ # SMTP server implementation
│ ├── outgoing/ # Email relay implementation
│ └── types/ # Type definitions
├── web/ # Web frontend files
├── go.mod # Go module definition
└── README.md # This document
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- MailDev - Original project inspiration
- emersion/go-smtp - SMTP server library
- emersion/go-message - Email parsing library
- Gin - Web framework
- gorilla/websocket - WebSocket library
If you encounter any issues or have suggestions, please submit them in GitHub Issues.
If this project helps you, please give it a Star ⭐!
OwlMail - A Go implementation of a mail development and testing tool, fully compatible with MailDev 🦉


