SMTP Examples
This page provides real-world examples of using MockForge SMTP for testing email workflows.
Table of Contents
- Testing User Registration
- Password Reset Flow
- Email Verification
- Newsletter Subscriptions
- CI/CD Integration
- Load Testing
- Multi-Language Applications
Testing User Registration
Scenario
Test that your application sends a welcome email when users register.
Fixture
fixtures/smtp/welcome-email.yaml
:
identifier: "welcome-email"
name: "Welcome Email"
description: "Auto-responds to new user registration"
match_criteria:
recipient_pattern: "^[^@]+@example\\.com$"
subject_pattern: "^Welcome"
response:
status_code: 250
message: "Message accepted"
auto_reply:
enabled: true
from: "noreply@example.com"
to: "{{from}}"
subject: "Welcome to Our Platform!"
body: |
Hi there!
Thank you for registering at our platform.
Click here to verify your email:
https://example.com/verify?token={{uuid}}
Best regards,
The Team
storage:
save_to_mailbox: true
Python Test
import smtplib
import requests
from email.message import EmailMessage
def test_user_registration_sends_welcome_email():
# Register a new user
response = requests.post('http://localhost:8080/api/register', json={
'email': 'newuser@example.com',
'password': 'SecurePass123',
'name': 'Test User'
})
assert response.status_code == 201
# Verify email was sent
# (In real scenario, you'd query MockForge's mailbox API)
# For now, manually check logs or implement mailbox checking
def send_test_email():
"""Helper to test fixture directly"""
msg = EmailMessage()
msg['Subject'] = 'Welcome to Our Platform'
msg['From'] = 'system@myapp.com'
msg['To'] = 'newuser@example.com'
msg.set_content('Welcome!')
with smtplib.SMTP('localhost', 1025) as server:
server.send_message(msg)
print("Test email sent!")
if __name__ == "__main__":
send_test_email()
Node.js Test
const nodemailer = require('nodemailer');
const axios = require('axios');
const assert = require('assert');
describe('User Registration', () => {
it('should send welcome email', async () => {
// Configure nodemailer to use MockForge
const transporter = nodemailer.createTransport({
host: 'localhost',
port: 1025,
secure: false,
});
// Register user
const response = await axios.post('http://localhost:8080/api/register', {
email: 'newuser@example.com',
password: 'SecurePass123',
name: 'Test User'
});
assert.strictEqual(response.status, 201);
// Send test email
await transporter.sendMail({
from: 'system@myapp.com',
to: 'newuser@example.com',
subject: 'Welcome to Our Platform',
text: 'Welcome!',
});
// In production, query MockForge mailbox API here
});
});
Password Reset Flow
Scenario
Test password reset email with temporary token.
Fixture
fixtures/smtp/password-reset.yaml
:
identifier: "password-reset"
name: "Password Reset"
match_criteria:
recipient_pattern: "^.*@.*$"
subject_pattern: "^Password Reset"
response:
status_code: 250
message: "Reset email accepted"
auto_reply:
enabled: true
from: "security@example.com"
to: "{{from}}"
subject: "Password Reset Instructions"
body: |
Hello,
You requested a password reset.
Click the link below to reset your password:
https://example.com/reset?token={{uuid}}
This link expires in 1 hour.
If you didn't request this, please ignore this email.
Security Team
storage:
save_to_mailbox: true
export_to_file: "./logs/password-resets"
Python Test
import pytest
import smtplib
from email.message import EmailMessage
def trigger_password_reset(email):
"""Trigger password reset in your application"""
import requests
response = requests.post('http://localhost:8080/api/password-reset',
json={'email': email})
return response.status_code == 200
def test_password_reset_email():
email = 'user@example.com'
# Trigger reset
assert trigger_password_reset(email)
# Verify email sent (check mailbox)
# TODO: Implement mailbox API check
def test_password_reset_invalid_email():
"""Test that invalid email is rejected"""
email = 'bounce-test@example.com' # Configured to fail
# This should fail
assert not trigger_password_reset(email)
Email Verification
Scenario
Test email verification link generation and sending.
Fixture
fixtures/smtp/email-verification.yaml
:
identifier: "email-verification"
name: "Email Verification"
match_criteria:
subject_pattern: "^Verify Your Email"
response:
status_code: 250
message: "Verification email sent"
auto_reply:
enabled: true
from: "noreply@example.com"
to: "{{from}}"
subject: "Verify Your Email Address"
body: |
Please verify your email address by clicking below:
https://example.com/verify?email={{to}}&code={{faker.alphanumeric 32}}
This link expires in 24 hours.
storage:
save_to_mailbox: true
Go Test
package main
import (
"net/smtp"
"testing"
)
func TestEmailVerification(t *testing.T) {
// Setup
smtpHost := "localhost:1025"
from := "system@myapp.com"
to := []string{"user@example.com"}
// Create message
message := []byte(
"Subject: Verify Your Email\r\n" +
"\r\n" +
"Please verify your email.\r\n",
)
// Send email
err := smtp.SendMail(smtpHost, nil, from, to, message)
if err != nil {
t.Fatalf("Failed to send email: %v", err)
}
// Verify sent (check mailbox)
// TODO: Implement mailbox check
}
Newsletter Subscriptions
Scenario
Test newsletter subscription confirmation emails.
Fixture
fixtures/smtp/newsletter.yaml
:
identifier: "newsletter-subscription"
name: "Newsletter Subscription"
match_criteria:
recipient_pattern: "^newsletter@example\\.com$"
response:
status_code: 250
message: "Subscription received"
auto_reply:
enabled: true
from: "newsletter@example.com"
to: "{{from}}"
subject: "Confirm Your Newsletter Subscription"
body: |
Thanks for subscribing to our newsletter!
Click to confirm: https://example.com/newsletter/confirm?email={{from}}
You'll receive our weekly digest every Monday.
storage:
save_to_mailbox: true
Ruby Test
require 'mail'
require 'minitest/autorun'
class NewsletterTest < Minitest::Test
def setup
Mail.defaults do
delivery_method :smtp,
address: "localhost",
port: 1025
end
end
def test_newsletter_subscription
email = Mail.new do
from 'user@test.com'
to 'newsletter@example.com'
subject 'Subscribe'
body 'Please subscribe me'
end
email.deliver!
# Verify subscription email sent
# TODO: Check MockForge mailbox
end
end
CI/CD Integration
GitHub Actions
.github/workflows/test.yml
:
name: Test Email Workflows
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
mockforge:
image: mockforge/mockforge:latest
ports:
- 1025:1025
env:
MOCKFORGE_SMTP_ENABLED: true
MOCKFORGE_SMTP_PORT: 1025
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install -r requirements.txt
- name: Run email tests
env:
SMTP_HOST: localhost
SMTP_PORT: 1025
run: |
pytest tests/test_emails.py -v
GitLab CI
.gitlab-ci.yml
:
test:
image: python:3.11
services:
- name: mockforge/mockforge:latest
alias: mockforge
variables:
MOCKFORGE_SMTP_ENABLED: "true"
SMTP_HOST: mockforge
SMTP_PORT: "1025"
script:
- pip install -r requirements.txt
- pytest tests/test_emails.py
Docker Compose
docker-compose.test.yml
:
version: '3.8'
services:
mockforge:
image: mockforge/mockforge:latest
ports:
- "1025:1025"
environment:
MOCKFORGE_SMTP_ENABLED: "true"
MOCKFORGE_SMTP_PORT: 1025
volumes:
- ./fixtures:/fixtures
app:
build: .
depends_on:
- mockforge
environment:
SMTP_HOST: mockforge
SMTP_PORT: 1025
command: pytest tests/
Load Testing
Scenario
Test application performance with high email volume.
Python Load Test
import concurrent.futures
import smtplib
from email.message import EmailMessage
import time
def send_email(index):
"""Send a single email"""
msg = EmailMessage()
msg['Subject'] = f'Load Test Email {index}'
msg['From'] = f'loadtest{index}@test.com'
msg['To'] = 'recipient@example.com'
msg.set_content(f'This is load test email #{index}')
try:
with smtplib.SMTP('localhost', 1025, timeout=5) as server:
server.send_message(msg)
return True
except Exception as e:
print(f"Error sending email {index}: {e}")
return False
def load_test(num_emails=1000, num_workers=10):
"""Send many emails concurrently"""
print(f"Starting load test: {num_emails} emails with {num_workers} workers")
start_time = time.time()
with concurrent.futures.ThreadPoolExecutor(max_workers=num_workers) as executor:
results = list(executor.map(send_email, range(num_emails)))
end_time = time.time()
duration = end_time - start_time
success_count = sum(results)
emails_per_second = num_emails / duration
print(f"\nResults:")
print(f" Total emails: {num_emails}")
print(f" Successful: {success_count}")
print(f" Failed: {num_emails - success_count}")
print(f" Duration: {duration:.2f}s")
print(f" Throughput: {emails_per_second:.2f} emails/sec")
if __name__ == "__main__":
load_test(num_emails=1000, num_workers=20)
Configuration for Load Testing
smtp:
enabled: true
port: 1025
host: "0.0.0.0"
max_connections: 500
max_mailbox_messages: 10000
timeout_secs: 60
Multi-Language Applications
Scenario
Test internationalized email content.
Fixture with Template
fixtures/smtp/i18n-welcome.yaml
:
identifier: "i18n-welcome"
name: "Internationalized Welcome"
match_criteria:
recipient_pattern: "^[^@]+@example\\.com$"
subject_pattern: "^Welcome|Bienvenue|Willkommen"
response:
status_code: 250
message: "Message accepted"
auto_reply:
enabled: false # Handle in application
storage:
save_to_mailbox: true
Python Multi-Language Test
import smtplib
from email.message import EmailMessage
from email.mime.text import MIMEText
def send_welcome_email(recipient, language='en'):
"""Send welcome email in specified language"""
subjects = {
'en': 'Welcome to Our Platform',
'fr': 'Bienvenue sur notre plateforme',
'de': 'Willkommen auf unserer Plattform',
'es': 'Bienvenido a nuestra plataforma'
}
bodies = {
'en': 'Welcome! Thank you for registering.',
'fr': 'Bienvenue! Merci de vous être inscrit.',
'de': 'Willkommen! Danke für Ihre Registrierung.',
'es': '¡Bienvenido! Gracias por registrarse.'
}
msg = EmailMessage()
msg['Subject'] = subjects.get(language, subjects['en'])
msg['From'] = 'noreply@example.com'
msg['To'] = recipient
msg['Content-Language'] = language
msg.set_content(bodies.get(language, bodies['en']))
with smtplib.SMTP('localhost', 1025) as server:
server.send_message(msg)
def test_multi_language_emails():
"""Test emails in multiple languages"""
languages = ['en', 'fr', 'de', 'es']
for lang in languages:
send_welcome_email(f'user-{lang}@example.com', lang)
print(f"Sent {lang} email")
if __name__ == "__main__":
test_multi_language_emails()
Testing Email Bounces
Scenario
Test application handling of bounced emails.
Fixture
fixtures/smtp/bounce-test.yaml
:
identifier: "bounce-simulation"
name: "Bounce Simulation"
match_criteria:
recipient_pattern: "^bounce@example\\.com$"
response:
status_code: 550
message: "Mailbox unavailable"
storage:
save_to_mailbox: false
behavior:
failure_rate: 1.0 # Always fail
Test
import smtplib
from email.message import EmailMessage
def test_bounce_handling():
"""Test that application handles bounces correctly"""
msg = EmailMessage()
msg['Subject'] = 'Test Bounce'
msg['From'] = 'sender@test.com'
msg['To'] = 'bounce@example.com'
msg.set_content('This should bounce')
try:
with smtplib.SMTP('localhost', 1025) as server:
server.send_message(msg)
assert False, "Expected SMTPRecipientsRefused"
except smtplib.SMTPRecipientsRefused as e:
# Expected behavior
print(f"Bounce handled correctly: {e}")
assert '550' in str(e)
Integration with Testing Frameworks
pytest Fixture
import pytest
import smtplib
from email.message import EmailMessage
@pytest.fixture
def smtp_client():
"""Provides SMTP client connected to MockForge"""
return smtplib.SMTP('localhost', 1025)
@pytest.fixture
def email_factory():
"""Factory for creating test emails"""
def _create_email(to, subject="Test", body="Test body"):
msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = 'test@test.com'
msg['To'] = to
msg.set_content(body)
return msg
return _create_email
def test_with_fixtures(smtp_client, email_factory):
"""Test using pytest fixtures"""
email = email_factory('user@example.com', subject='Welcome')
smtp_client.send_message(email)
# Verify email sent
unittest Helper
import unittest
import smtplib
class EmailTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""Set up SMTP connection for all tests"""
cls.smtp_host = 'localhost'
cls.smtp_port = 1025
def send_test_email(self, to, subject, body):
"""Helper method to send test emails"""
with smtplib.SMTP(self.smtp_host, self.smtp_port) as server:
# ... send email
pass
def test_email_sending(self):
self.send_test_email('test@example.com', 'Test', 'Body')
# Verify
Best Practices
- Use dedicated fixtures for each test scenario
- Clean mailbox between test runs
- Test both success and failure scenarios
- Verify email content, not just delivery
- Use realistic delays in load tests
- Test internationalization early
- Mock external dependencies completely
Troubleshooting
Emails Not Received
Check:
- SMTP server is running
- Correct port (1025)
- Fixture patterns match
- Mailbox not full
Slow Tests
Optimize:
- Reduce
delay_ms
in fixtures - Disable
save_to_mailbox
if not needed - Use concurrent connections in load tests
Fixture Not Matching
Debug:
- Enable debug logging
- Simplify regex patterns
- Test patterns with regex101.com
- Check fixture load order