pytestintermediate
pytest Transactional Email Test
Test transactional emails in Python with pytest
pytest Transactional Email Test (python)python
# tests/conftest.py
import pytest
import requests
import os
import time
@pytest.fixture
def plop():
"""Fixture providing plop.email API client."""
class PlopClient:
def __init__(self):
self.base_url = "https://api.plop.email/v1"
self.api_key = os.environ["PLOP_API_KEY"]
def get_latest(self, to: str, retries: int = 5, delay: float = 1.0):
"""Fetch latest email with retry logic."""
for attempt in range(retries):
response = requests.get(
f"{self.base_url}/messages/latest",
params={"to": to},
headers={"Authorization": f"Bearer {self.api_key}"},
)
data = response.json()
if response.status_code == 200 and "error" not in data:
return data
time.sleep(delay)
raise TimeoutError(f"Email not received after {retries} attempts")
def get_all(self, mailbox: str):
"""Fetch all emails for a mailbox."""
response = requests.get(
f"{self.base_url}/messages",
params={"mailbox": mailbox},
headers={"Authorization": f"Bearer {self.api_key}"},
)
return response.json()
return PlopClient()
@pytest.fixture
def test_email():
"""Generate unique test email address."""
def _generate(prefix: str = "test"):
timestamp = int(time.time() * 1000)
return f"{prefix}+{timestamp}@in.plop.email"
return _generate
# tests/test_emails.py
import pytest
from myapp.email import send_order_confirmation, send_shipping_notification
class TestOrderEmails:
def test_order_confirmation_includes_items(self, plop, test_email):
"""Order confirmation should list all items with prices."""
email = test_email("order")
order = {
"id": "ORD-123",
"items": [
{"name": "Widget", "price": 29.99, "qty": 2},
{"name": "Gadget", "price": 49.99, "qty": 1},
],
"total": 109.97,
}
send_order_confirmation(to=email, order=order)
received = plop.get_latest(email)
assert "Order Confirmation" in received["subject"]
assert "ORD-123" in received["htmlContent"]
assert "Widget" in received["htmlContent"]
assert "$29.99" in received["htmlContent"]
assert "$109.97" in received["htmlContent"]
def test_shipping_notification_has_tracking(self, plop, test_email):
"""Shipping notification should include tracking link."""
email = test_email("shipping")
send_shipping_notification(
to=email,
order_id="ORD-123",
tracking_number="1Z999AA10123456784",
carrier="UPS",
)
received = plop.get_latest(email)
assert "shipped" in received["subject"].lower()
assert "1Z999AA10123456784" in received["htmlContent"]
assert "track" in received["htmlContent"].lower()
@pytest.mark.parametrize("locale,expected", [
("en", "Your order has shipped"),
("es", "Tu pedido ha sido enviado"),
("fr", "Votre commande a été expédiée"),
])
def test_shipping_localization(self, plop, test_email, locale, expected):
"""Shipping emails should be localized."""
email = test_email(f"locale-{locale}")
send_shipping_notification(
to=email,
order_id="ORD-123",
tracking_number="TRACK123",
carrier="UPS",
locale=locale,
)
received = plop.get_latest(email)
assert expected in received["htmlContent"]How It Works
1
pytest Fixtures
We create reusable fixtures for the plop client and test email generation. Fixtures keep tests DRY and readable.
2
Retry Logic
The get_latest method includes retry logic to handle email delivery delays gracefully.
3
Parametrized Tests
The localization test uses @pytest.mark.parametrize to test multiple languages with the same test logic.
4
Real Data Testing
We test with realistic order data to verify the email template handles real-world content correctly.