MailBrew REST API Reference
MailBrew can be used in two ways.
Point your app's SMTP to MailBrew (smtp.mailbrew.dev). View sent emails in your dashboard's shared inbox in real time.
SMTP Config →Create test email addresses via API, receive real emails, and automate OTP extraction, link verification, and email assertions. CI/CD ready.
Cloud API →Set the following environment variables in your application.
Use SMTP credentials generated in the Dashboard "SMTP Settings" page. All emails sent with these credentials are automatically routed to your company's shared inbox, regardless of the recipient address. No need to worry about recipient addresses during testing.
Connections are encrypted. Use port 587 (STARTTLS, recommended) or 465 (SSL/TLS). Port 587 refuses authentication until the connection is encrypted.
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailbrew.dev
MAIL_PORT=587
MAIL_USERNAME=mb_smtp_xxxxx
MAIL_PASSWORD=your_smtp_password
MAIL_ENCRYPTION=tlsLaravel 11+ encrypts automatically with MAIL_PORT=587 (MAIL_ENCRYPTION=tls is for Laravel 10 and earlier). For port 465 use MAIL_PORT=465 and MAIL_SCHEME=smtps (MAIL_ENCRYPTION=ssl on Laravel 10 and earlier).
For Node.js (Nodemailer):
const transporter = nodemailer.createTransport({
host: 'smtp.mailbrew.dev',
port: 587,
secure: false, // STARTTLS on 587 (for 465: port: 465, secure: true)
requireTLS: true,
auth: {
user: 'mb_smtp_xxxxx',
pass: 'your_smtp_password',
},
});Emails sent to MailBrew can be viewed in real-time via the Web UI. Supports HTML preview, attachment downloads, and full-text search.
https://tokyo-rehearsal.mailbrew.devThe following are MailBrew cloud service API endpoints. Authentication with an API key is required.
Use our official SDKs for easy API integration.
npm install @mailbrew/sdkconst { MailBrew } = require('@mailbrew/sdk');
const client = new MailBrew('mb_your_key_here');createAddress(options?)Create a temporary email address
const addr = await client.createAddress({ ttl: 3600 });
console.log(addr.address); // "ax7k2m@acme.mailbrew.dev"listAddresses()List all addresses
const addresses = await client.listAddresses();deleteAddress(address)Delete an address
await client.deleteAddress('ax7k2m@acme.mailbrew.dev');waitForEmail(address, options?)Wait for email via long-polling
const email = await client.waitForEmail(addr.address, { timeout: 30000 });listEmails(address)List emails for an address
const emails = await client.listEmails(addr.address);getEmail(address, emailId)Get email details
const detail = await client.getEmail(addr.address, email.id);extractOtp(address, emailId, options?)Extract OTP/verification code from email
const code = await client.extractOtp(addr.address, email.id);
// Custom pattern: { pattern: '\\d{4}' }extractLinks(address, emailId, options?)Extract links from email
const links = await client.extractLinks(addr.address, email.id);
// Filter: { pattern: 'verify' }assertEmail(address, emailId, assertions)Assert email properties (subject, from, body, etc.)
const result = await client.assertEmail(addr.address, email.id, {
subject_contains: 'Welcome',
body_contains: 'verify',
});
console.log(result.passed); // truecaptureOtp(options?)Create address + wait + extract OTP in one call
const { address, waitAndExtract } = await client.captureOtp({ ttl: 120 });
// ... trigger email ...
const { code, email } = await waitAndExtract();forwardEmail(address, emailId, to)Forward email to an active, verified member of your company
await client.forwardEmail(addr.address, email.id, 'dev@example.com');createWebhook(url, options?)Create a global webhook
const wh = await client.createWebhook('https://example.com/hook', {
events: ['email.received'],
});listWebhooks()List webhooks
const webhooks = await client.listWebhooks();deleteWebhook(id)Delete a webhook
await client.deleteWebhook(wh.id);All API requests require an API key. Include it in the X-API-Key header.
X-API-Key: mb_your_key_hereIf an API key has scopes assigned, requests without the required scope will return a 403 error. Keys without scopes have full access.
addresses:read— List and view addressesaddresses:write— Create addressesaddresses:delete— Delete addressesemails:read— List, wait for, extract OTP and links, assert, diff and check deliverabilityemails:forward— Forward emails to active, verified members of your companywebhooks:read— List webhookswebhooks:write— Create and update webhookswebhooks:delete— Delete webhooksGenerated addresses use your company subdomain. If a custom domain is configured, it will be used instead.
{random}@{company-slug}.mailbrew.devhttps://tokyo-rehearsal.mailbrew.dev/api/mailbrewCommon causes for each status.
401403404410422429The language of error messages follows the Accept-Language header (send Accept-Language: ja for Japanese). Without it, messages are in English. Identifiers such as scope names (emails:read) and codes are written the same way in every language.
The response headers tell you how many calls you have left.
Retry-AfterX-RateLimit-LimitX-RateLimit-RemainingEvery delivery carries X-Mailbrew-Timestamp (the send time in UNIX seconds) and X-Mailbrew-Signature: sha256=…. Compare the received signature with the HMAC-SHA256 of "{timestamp}.{body}" computed with your signing secret, and compare them in constant time. Use the raw body bytes, and reject anything whose timestamp differs from the current time by more than 300 seconds (5 minutes).
X-Mailbrew-TimestampX-Mailbrew-Signatureconst timestamp = req.get('X-Mailbrew-Timestamp') || '';
if (!/^\d+$/.test(timestamp)) return res.sendStatus(401);
if (Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp)) > 300) return res.sendStatus(401);
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.MAILBREW_WEBHOOK_SECRET)
.update(timestamp + '.').update(req.body).digest('hex');
const received = Buffer.from(req.get('X-Mailbrew-Signature') || '');
const expectedBuffer = Buffer.from(expected);
if (received.length !== expectedBuffer.length || !crypto.timingSafeEqual(received, expectedBuffer)) {
return res.sendStatus(401);
}You can find the signing secret on the Webhooks page of the dashboard (owners only). Deliveries to a per-address webhook_url are signed with your company signing secret.
/api/mailbrew/addressesCreate Address — Generate an email address. Set ttl=0 to create a permanent (non-expiring) address.
ttlintegerwebhook_urlstringlocal_partstring{
"data": {
"id": 1,
"address": "ax7k2m@acme.mailbrew.dev",
"webhook_url": null,
"expires_at": "2026-03-29T13:00:00+00:00",
"is_permanent": false,
"created_at": "2026-03-29T12:00:00+00:00"
}
}/api/mailbrew/addressesList Addresses — Returns the addresses created with this API key and the addresses auto-created on receipt for the same company. Auto-created addresses can be read with any API key from the same company.
{
"data": [
{
"id": 1,
"address": "ax7k2m@acme.mailbrew.dev",
"webhook_url": null,
"expires_at": "2026-03-29T13:00:00+00:00",
"is_permanent": false,
"created_at": "2026-03-29T12:00:00+00:00"
}
]
}/api/mailbrew/addresses/{address}Get Address — Get details of an address.
{
"data": {
"id": 1,
"address": "ax7k2m@acme.mailbrew.dev",
"webhook_url": null,
"expires_at": "2026-03-29T13:00:00+00:00",
"is_permanent": false,
"created_at": "2026-03-29T12:00:00+00:00"
}
}/api/mailbrew/addresses/{address}/emailsList Emails — List emails received at the specified address. Emails are deleted after the retention period (7 days on every plan; organizations can shorten it in Security settings).
{
"data": [
{
"id": 1,
"from_address": "noreply@example.com",
"subject": "Your verification code",
"text_body": "Your code is: 847291",
"received_at": "2026-03-29T12:05:00+00:00"
}
]
}/api/mailbrew/addresses/{address}/emails/{id}Get Email — Get details of a specific email.
{
"data": {
"id": 1,
"from_address": "noreply@example.com",
"subject": "Your verification code",
"text_body": "Your code is: 847291",
"html_body": "<p>Your code is: <b>847291</b></p>",
"received_at": "2026-03-29T12:05:00+00:00"
}
}/api/mailbrew/addresses/{address}/emails/{id}/otpExtract OTP — Auto-extract OTP/verification codes from email body. Perfect for E2E tests.
patternstring{
"data": {
"code": "847291",
"email_id": 1,
"source": "text_body"
}
}/api/mailbrew/addresses/{address}/emails/{id}/linksExtract Links — Auto-extract links (URLs) from email body. Perfect for invitation links and password reset flows.
patternstring{
"data": {
"links": [
"https://example.com/verify?token=abc123",
"https://example.com/unsubscribe"
],
"email_id": 1,
"source": "text_body"
}
}/api/mailbrew/addresses/{address}/emails/{id}/assertAssert Email — Validate email content. Check subject, sender, recipient, and body content simultaneously.
subjectstringsubject_containsstringfromstringtostringbody_containsstring{
"data": {
"passed": true,
"email_id": 1,
"results": [
{ "field": "subject", "passed": true, "expected": "Welcome", "actual": "Welcome" },
{ "field": "body_contains", "passed": true, "expected": "verify" }
]
}
}/api/mailbrew/addresses/{address}/emails/{id}/forwardForward Email — Forward a received email only to an active, verified member of your company.
tostring{
"data": {
"forwarded": true,
"to": "dev@example.com"
},
"success": true
}/api/mailbrew/addresses/{address}Delete Address — Delete an address.
204 No Content/api/mailbrew/addresses/{address}/emails/waitWait for Emails — Wait for emails using long-polling.
timeoutintegersincestringcountinteger{ "data": [] }/api/mailbrew/addresses/{address}/sequenceVerify Email Sequence — Verify that matching emails arrive in order.
stepsarraytimeoutinteger{ "data": { "passed": true, "steps": [] } }/api/mailbrew/addresses/{address}/emails/{id}/diffCompare Emails — Compare two emails.
againstinteger{ "data": { "email_id": 1, "against_id": 2, "fields": {} } }/api/mailbrew/addresses/{address}/emails/{id}/deliverabilityAnalyze Deliverability — Analyze deliverability including SPF, DKIM, and DMARC.
{ "data": { "score": 100, "checks": [], "recommendations": [] } }/api/mailbrew/emailsList Captured Emails — List emails sent over SMTP AUTH to external recipients (e.g. gmail.com), looked up by envelope recipient (RCPT TO), including BCC. A MailBrew address cannot be used as to (use the address endpoints). Get one, extract OTP or links with /api/mailbrew/emails/{id}, /otp and /links.
tostringsincestring{
"data": [
{
"id": 1,
"from_address": "noreply@example.com",
"subject": "Your verification code",
"text_body": "Your code is: 847291",
"received_at": "2026-03-29T12:05:00+00:00"
}
]
}/api/mailbrew/emails/waitWait for Captured Emails — Wait for captured emails using long-polling. Same parameters as waiting on an address.
tostringtimeoutintegersincestringcountinteger{ "data": [] }/api/mailbrew/webhooksList Webhooks — List global webhooks.
{
"data": [
{
"id": 1,
"url": "https://example.com/hook",
"events": ["email.received"],
"is_active": true
}
]
}/api/mailbrew/webhooksCreate Webhook — Register a global webhook. Notifies for all addresses.
urlstringeventsarray{
"data": {
"id": 1,
"url": "https://example.com/hook",
"secret": "abc123...",
"events": ["email.received"],
"is_active": true
}
}/api/mailbrew/webhooks/{id}Update Webhook — Update a webhook URL, events, or active state.
urlstringeventsarrayis_activeboolean{ "data": { "id": 1, "url": "https://example.com/hook", "events": ["email.received"], "is_active": true } }/api/mailbrew/webhooks/{id}Delete Webhook — Delete a webhook.
204 No Contentconst { MailBrew } = require('@mailbrew/sdk');
const client = new MailBrew('mb_your_key_here');
// E2E test: create address, wait for email, extract OTP
const { address, waitAndExtract } = await client.captureOtp({ ttl: 120 });
// ... trigger email send to `address` ...
const { code, email } = await waitAndExtract();
console.log(code); // "847291"