Email (Mailpit)
Assert on the emails an application sends, and follow their links and codes.
How to point an environment at Mailpit, wait for a verification email, open its link or read a one-time code, and keep scenarios from reading each other's mail.
Signup verification, invitations, password reset and emailed 2FA all go through an inbox. The email steps read a Mailpit mail catcher: the application under test sends SMTP to Mailpit, and the steps read Mailpit's REST API.
Set up
Run Mailpit next to the application and point the application's SMTP settings at port 1025:
docker run -d --name mailpit -p 8025:8025 -p 1025:1025 axllent/mailpitDeclare it in the environment yaml. url is the web/API port, not SMTP:
mail:
provider: mailpit
url: http://localhost:8025A Mailpit started with --ui-auth-file needs auth: { type: basic, username: qa, password: '${MAILPIT_PASSWORD}' }. The password is refused as a literal. pollIntervalMs, clockSkewMs and timeoutSeconds are in the env yaml reference.
Verify a signup
@hybrid @regression
Scenario: A new user verifies their email
Given I generate a "user" from the factory as "user"
And I clear the inbox for "{{user.email}}"
And I navigate to the "signup" page
When I fill the "Email" field with "{{user.email}}"
And I click the "Create account" button
Then the inbox for "{{user.email}}" should receive an email with subject containing "Verify" within 30 seconds
And the latest email to "{{user.email}}" should have been sent from "no-reply@my-app.test"
When I open the link "Verify email" from the latest email to "{{user.email}}"
Then I should see the text "Your email is verified"For an emailed one-time code, save it with a capture group and type it in:
Then the inbox for "{{user.email}}" should receive an email with subject containing "sign-in code" within 30 seconds
When I save the code matching "code is (\d{6})" from the latest email to "{{user.email}}" as "otp"
And I fill the "Code" field with "{{otp}}"I save the link matching saves a URL instead, for an API step to call or a later step to open.
Keep scenarios independent
- Each scenario only sees mail received after it started, and "the latest email" is the one the last
should receivestep matched. The full rules are under Which email is "the latest". - Use a unique address per scenario where the application allows it. Factories are seeded per scenario, so a retry regenerates the same address: start with
I clear the inbox forso a retry cannot read the first attempt's email. - A fixed address shared between scenarios, such as a seeded account, needs
I clear the inbox forand a run that does not use that address in parallel. - There are no sleeps: every wait polls Mailpit and returns as soon as the email is there.