When debugging applications that send emails, you often need to verify email sending behavior without actually delivering messages. Common scenarios include:
- Testing email sending frequency (like your case of 7x over-sending)
- Validating email content formatting
- Checking recipient addressing
- Performance testing under heavy email loads
Python's standard library includes smtpd
which is perfect for this:
import smtpd
import asyncore
from datetime import datetime
class CustomSMTPServer(smtpd.SMTPServer):
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
timestamp = datetime.now().strftime("[%Y-%m-%d %H:%M:%S]")
with open("mail.log", "a") as log:
log.write(f"{timestamp} sent mail to {', '.join(rcpttos)}\n")
return
server = CustomSMTPServer(('localhost', 1025), None)
asyncore.loop()
For those who prefer pre-built solutions:
- MailCatcher: Ruby-based with web interface (runs on port 1080)
- FakeSMTP: Java-based with GUI (standalone JAR file)
- MailHog: Written in Go with API and web UI
Configure your app to use the dummy server:
# For Python applications using smtplib
import smtplib
smtp = smtplib.SMTP('localhost', 1025)
smtp.sendmail(
'from@example.com',
['to@example.com'],
'Subject: Test\n\nBody content'
)
Enhance the basic logger to capture more details:
class EnhancedSMTPServer(smtpd.SMTPServer):
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
timestamp = datetime.now().isoformat()
log_entry = {
"timestamp": timestamp,
"sender": mailfrom,
"recipients": rcpttos,
"size": len(data),
"client": f"{peer[0]}:{peer[1]}"
}
with open("mail.jsonl", "a") as log:
log.write(json.dumps(log_entry) + "\n")
For containerized environments:
# docker-compose.yml
version: '3'
services:
smtp:
image: mailhog/mailhog
ports:
- "1025:1025"
- "8025:8025"
When debugging email-sending functionality in applications, you often encounter situations where emails are being sent unexpectedly or in incorrect quantities. A local SMTP server that captures but doesn't actually send emails is invaluable for testing.
Several open-source projects provide this functionality:
- MailCatcher: Ruby-based, provides web interface
- FakeSMTP: Java-based, GUI application
- MailHog: Go-based, API and web interface
For those who prefer a lightweight solution, here's a minimal Python SMTP server that logs to console:
import smtpd
import asyncore
from datetime import datetime
class CustomSMTPServer(smtpd.SMTPServer):
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
timestamp = datetime.now().strftime("[%Y-%m-%d %H:%M:%S]")
print(f"{timestamp} Mail from: {mailfrom}, To: {rcpttos}")
return None
server = CustomSMTPServer(('localhost', 1025), None)
asyncore.loop()
Save the code to a file (e.g., fake_smtp.py
) and run:
python fake_smtp.py
Point your application's SMTP settings to:
- Host:
localhost
- Port:
1025
- Authentication: None required
To log to a file instead of console, modify the process_message
method:
def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
timestamp = datetime.now().strftime("[%Y-%m-%d %H:%M:%S]")
with open("mail.log", "a") as f:
f.write(f"{timestamp} Mail from: {mailfrom}, To: {', '.join(rcpttos)}\n")
return None
For containerized environments, MailHog provides a ready-to-use solution:
docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog