Im using cypress for behaviour testing my meteor 3 app. One of those tests checks the content of the registration email, ‘clicks’ the registration link and sets the new users password, thus checking the new user storyboard. I thought I might share some pointers on how to do this in case its useful.
The relevant section of the test looks like:
    cy.get("input[name='username']").type('ella')
    cy.get("input[name='email']").type('ella@test.com')
    cy.get("input[name='firstName']").type('Ella')
    cy.get("input[name='lastName']").type('User')
    cy.get('button').contains('OK').click()
    cy.wait(500) // allow some time for email to register
    cy.get('#account-dropdown').click()
    cy.get('a.dropdown-item').contains('Sign out').click()
    // capture contents of enrollment email and then visit the link contained
    cy.task('getLastEmail', 'ella@test.com').then((email) => {
      const url = email.body.match(/http:\/\/.*/g)[0]
      cy.visit(url)
      cy.get("input[name='newpassword1']").type('password')
      cy.get("input[name='newpassword2']").type('password')
      cy.get('button').contains('Set Password').click()
      cy.contains('Hello Ella')
    })
Where the user has previously authenticated as a user that has the authority to add a new users. The important bit is the getLastEmail cypress task which is defined in the cypress.config.js file:
const { defineConfig } = require('cypress')
const ms = require('smtp-tester')
module.exports = defineConfig({
  e2e: {
    setupNodeEvents(on) {
      // see https://www.cypress.io/blog/testing-html-emails-using-cypress for useful background
      // starts the SMTP server at localhost:7777
      const port = 7777
      const mailServer = ms.init(port)
      console.log('mail server at port %d', port)
      // [receiver email]: email text
      let lastEmail = {}
      const handler = (addr, id, email) => {
        // store the email by the receiver email
        lastEmail[email.headers.to] = {
          body: email.body,
          html: email.html,
        }
      }
      // process all emails
      mailServer.bind(handler)
      on('task', {
        getLastEmail(userEmail) {
          // cy.task cannot return undefined
          // thus we return null as a fallback
          return lastEmail[userEmail] || null
        },
      })
      on('after:run', () => {
        mailServer.unbind(handler)
        mailServer.stop()
      })
    },
    baseUrl: 'http://localhost:3000'
  },
...
Hopefully this might be useful to others trying to do the same thing. And please do tell me if you see something dumb.