Testing subject, sender, recipient and timestamps
The envelope around the body: who sent it, exactly which address it reached, what the subject line said and when it landed.
How it works
Body assertions tell you the copy is right. Property assertions tell you the message was addressed, branded and timed correctly — which is where most transactional email bugs actually live.
Subject and sender
The two fields a user sees before opening anything.
msg = inbox.latest()
assert msg.subject == "Verify your email"
assert msg.sender == "no-reply@staging.example.com"
The exact recipient
to_address is the address the message was really delivered to, tag included. Useful when one inbox serves several signups.
assert msg.to_address == "shop+newsletter@a7f2c.mailflat.net"
When it landed
received_at is ISO 8601 in UTC. Assert that the mail belongs to this test run rather than a previous one.
from datetime import datetime, timedelta, timezone
landed = datetime.fromisoformat(msg.received_at)
assert datetime.now(timezone.utc) - landed < timedelta(minutes=2)
Worth knowing
Isolate instead of filtering by time
Time windows are a workaround for a shared mailbox. Give each test its own inbox and every message in it belongs to that test by construction.
See also
Tags and plus-addressing
One inbox, many senders: add a plus tag to the address and MailFlat records it as a field you can filter on.
Waiting and timeoutsMail is asynchronous, so every email test waits for something. The difference between a solid suite and a flaky one is how that wait is written.
HTML contentCheck the rendered half of a message: the HTML body is delivered exactly as it arrived, so you can assert on markup, buttons and merge fields.