Email utilities
SDK functions for generating disposable email addresses and reading received emails in tests.
Overview
The Heal SDK provides helpers for testing email flows without requiring an external mail service. Common examples include: sign-up confirmations, magic-link logins, password resets and email confirmations. Each organisation is assigned an email namespace on the Heal email tester domain: *.<org-slug>@tester-heal.dev.
| Method | What it does |
|---|---|
Heal.getEmail() | Returns a unique inbox address for this test run |
Heal.readLastEmail(address, options?) | Reads the most recent email at that address |
Heal.emailLogin(address, since) | Extracts a magic link from a login email |
Heal.emailSignup(type, address, since) | Extracts a confirmation code or link from a sign-up email |
How it works
These methods run server-side through heal's proxy: when the SDK is called, the request is sent to the Heal server which handles the email retrieval. All four methods poll until the email arrives, with a default timeout of 5 minutes.
Email namespace
Each organisation gets a dedicated inbox namespace:
*.<org-slug>@tester-heal.devAny address of the form anything.<org-slug>@tester-heal.dev is valid and routable. You can find your org slug in the Organisation tab of the Heal dashboard.
For example, if your slug is acme, then confirm.acme@tester-heal.dev, reset.acme@tester-heal.dev, or any address Heal.getEmail() returns will all land in inboxes your tests can read.
Heal.getEmail()
Returns a unique disposable address scoped to the current test run, within your organisation's namespace. This is useful for running many tests in parallel without email collisions.
static getEmail(): Promise<string>;Example
const email = await Heal.getEmail();
// e.g. "abc123.acme@tester-heal.dev"
await page.goto('https://app.example.com/signup');
await agent.healType('the email field', email);
await agent.healType('the password field', 'Test1234!');
await agent.healClick('the Sign up button');Heal.readLastEmail(address, options?)
Polls for and returns the most recent email delivered to the given address. Pass a since date (captured just before the action that triggers the email) so stale messages are ignored.
static readLastEmail(
address: string,
options?: { since?: Date; timeout?: number }
): Promise<Email>;| Option | Type | Default | Description |
|---|---|---|---|
since | Date | — | Ignore emails older than this timestamp |
timeout | number | 300000 (5 min) | How long to poll before timing out (ms) |
Example
const since = new Date();
await agent.healClick('the Send confirmation email button');
const message = await Heal.readLastEmail(emailAddress, { since, timeout: 30_000 });
const link = message.body.match(/https:\/\/\S+confirm\S+/)?.[0];
if (!link) throw new Error('Confirmation link not found');
await page.goto(link);
await agent.healAssert('account is confirmed');Heal.emailLogin(address, since)
Polls for a login email and extracts the magic link from it. Shorthand for readLastEmail + link extraction for login flows.
static emailLogin(address: string, since: Date): Promise<string>;Example
const since = new Date();
await agent.healClick('the Send magic link button');
const magicLink = await Heal.emailLogin(email, since);
await page.goto(magicLink);
await agent.healAssert('user is logged in');Heal.emailSignup(type, address, since)
Polls for a sign-up confirmation email and extracts either a confirmation code or a confirmation link depending on type.
static emailSignup(
type: 'confirmationCode' | 'confirmationLink',
address: string,
since: Date
): Promise<string>;Example — confirmation code
const since = new Date();
await agent.healClick('the Sign up button');
const code = await Heal.emailSignup('confirmationCode', email, since);
await agent.healType('the confirmation code field', code);
await agent.healClick('the Confirm button');Example — confirmation link
const since = new Date();
await agent.healClick('the Sign up button');
const link = await Heal.emailSignup('confirmationLink', email, since);
await page.goto(link);
await agent.healAssert('email is confirmed');Full example: parallel tests without collisions
Because Heal.getEmail() returns a unique address per test run, two tests signing up at the same time each get their own inbox without collisions.
import { Heal } from '@heal-dev/sdk';
test('user can sign up and confirm their email', async () => {
const heal = await Heal.init({ headless: true });
try {
const { page, agent } = await heal.getPage();
const email = await Heal.getEmail();
// e.g. "abc123.acme@tester-heal.dev"
const since = new Date();
await page.goto('https://app.example.com/signup');
await agent.healType('the email field', email);
await agent.healType('the password field', 'Test1234!');
await agent.healClick('the Sign up button');
await agent.healAssert('a confirmation email has been sent');
const link = await Heal.emailSignup('confirmationLink', email, since);
await page.goto(link);
await agent.healAssert('the email address is confirmed');
} finally {
await heal.close();
}
});import { Heal } from '@heal-dev/sdk';
test('user can sign up and confirm their email', async () => {
const heal = await Heal.init({ headless: true });
try {
const { page, agent } = await heal.getPage();
const email = await Heal.getEmail();
// e.g. "xyz789.acme@tester-heal.dev" — different address, same test
const since = new Date();
await page.goto('https://app.example.com/signup');
await agent.healType('the email field', email);
await agent.healType('the password field', 'Test1234!');
await agent.healClick('the Sign up button');
await agent.healAssert('a confirmation email has been sent');
const link = await Heal.emailSignup('confirmationLink', email, since);
await page.goto(link);
await agent.healAssert('the email address is confirmed');
} finally {
await heal.close();
}
});Related pages
- SDK overview: SDK overview
- SMS utilities: SMS utilities
- Full API reference: SDK reference