Email API and message workflows
Documentation navigation
Send, receive, search, and inspect emails and attachments with MailSlurp inbox APIs for applications, automations, and end-to-end tests.
MailSlurp can send and receive emails and attachments. Let us cover some common functions.
Quick links
Set up the SDK
The examples on this page use the MailSlurp SDK for JavaScript, Python, Java or C#. Choose a language once and every example on the page switches to it. Install the SDK for your language, set MAILSLURP_API_KEY in your server or test environment, then create a client:
JavaScript
import { MailSlurp } from 'mailslurp-client';
export function createClient() {
const apiKey = process.env.MAILSLURP_API_KEY;
if (!apiKey) throw new Error('Set MAILSLURP_API_KEY');
return new MailSlurp({ apiKey });
}
Python
import base64
import os
import mailslurp_client
def create_client():
api_key = os.environ.get("MAILSLURP_API_KEY")
if not api_key:
raise RuntimeError("Set MAILSLURP_API_KEY")
configuration = mailslurp_client.Configuration()
configuration.api_key["x-api-key"] = api_key
return mailslurp_client.ApiClient(configuration)
Java
import com.mailslurp.apis.*;
import com.mailslurp.clients.ApiClient;
import com.mailslurp.clients.ApiException;
import com.mailslurp.models.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
final class EmailSetup {
static ApiClient createClient() {
String apiKey = System.getenv("MAILSLURP_API_KEY");
if (apiKey == null || apiKey.trim().isEmpty()) {
throw new IllegalStateException("Set MAILSLURP_API_KEY");
}
ApiClient client = new ApiClient();
client.setApiKey(apiKey);
client.setConnectTimeout(10_000);
client.setReadTimeout(75_000);
return client;
}
}
C#
using System;
using System.Collections.Generic;
using System.Text;
using mailslurp.Api;
using mailslurp.Client;
using mailslurp.Model;
public static class EmailSetup
{
public static Configuration CreateConfiguration()
{
var apiKey = Environment.GetEnvironmentVariable("MAILSLURP_API_KEY");
if (string.IsNullOrWhiteSpace(apiKey))
throw new InvalidOperationException("Set MAILSLURP_API_KEY");
var configuration = new Configuration { Timeout = TimeSpan.FromSeconds(75) };
configuration.ApiKey.Add("x-api-key", apiKey);
return configuration;
}
}
The complete email examples include dependency files for each language.
Sending emails

To send emails first create an inbox. Then use the dashboard compose page or the send methods on the inbox controller. This example sends an HTML email and returns once MailSlurp accepts it:
JavaScript
export async function sendHtml(mailslurp, inboxId, to) {
// sendEmailAndConfirm returns the sent email record once MailSlurp accepts it.
return mailslurp.inboxController.sendEmailAndConfirm({
inboxId,
sendEmailOptions: {
to: [to],
subject: 'Your order has shipped',
body: '<h1>On its way</h1><p>Track it at <a href="https://example.com/track">example.com</a></p>',
isHTML: true,
},
});
}
Python
def send_html(api_client, inbox_id, to):
# send_email_and_confirm returns the sent email record once MailSlurp accepts it.
return mailslurp_client.InboxControllerApi(api_client).send_email_and_confirm(
inbox_id,
mailslurp_client.SendEmailOptions(
to=[to],
subject="Your order has shipped",
body='<h1>On its way</h1><p>Track it at <a href="https://example.com/track">example.com</a></p>',
is_html=True,
),
)
Java
public static SentEmailDto sendHtml(ApiClient client, UUID inboxId, String to) throws ApiException {
// sendEmailAndConfirm returns the sent email record once MailSlurp accepts it.
return new InboxControllerApi(client).sendEmailAndConfirm(inboxId, new SendEmailOptions()
.to(Collections.singletonList(to))
.subject("Your order has shipped")
.body("<h1>On its way</h1><p>Track it at <a href=\"https://example.com/track\">example.com</a></p>")
.isHTML(true)).execute();
}
C#
public static SentEmailDto SendHtml(Configuration configuration, Guid inboxId, string to)
{
// SendEmailAndConfirm returns the sent email record once MailSlurp accepts it.
return new InboxControllerApi(configuration).SendEmailAndConfirm(inboxId, new SendEmailOptions(
to: new List<string> { to },
subject: "Your order has shipped",
body: "<h1>On its way</h1><p>Track it at <a href=\"https://example.com/track\">example.com</a></p>",
isHTML: true));
}
Info. Sending to non-MailSlurp domains is enabled for free accounts. Paid accounts must use double opt-in consent to send external recipients or whitelist domains with support.
Sending attachments
To send an attachment, upload the file with the attachment controller, then send an email that lists the returned attachment ID:
JavaScript
export async function sendAttachment(mailslurp, inboxId, to) {
// Upload the file first, then send its attachment ID with the email.
const [attachmentId] = await mailslurp.attachmentController.uploadAttachment({
uploadAttachmentOptions: {
base64Contents: Buffer.from('id,total\n1001,49.00\n').toString('base64'),
contentType: 'text/csv',
filename: 'invoice.csv',
},
});
return mailslurp.inboxController.sendEmailAndConfirm({
inboxId,
sendEmailOptions: { to: [to], subject: 'Invoice attached', body: 'See attached.', attachments: [attachmentId] },
});
}
Python
def send_attachment(api_client, inbox_id, to):
# Upload the file first, then send its attachment ID with the email.
attachment_ids = mailslurp_client.AttachmentControllerApi(api_client).upload_attachment(
mailslurp_client.UploadAttachmentOptions(
base64_contents=base64.b64encode(b"id,total\n1001,49.00\n").decode(),
content_type="text/csv",
filename="invoice.csv",
)
)
return mailslurp_client.InboxControllerApi(api_client).send_email_and_confirm(
inbox_id,
mailslurp_client.SendEmailOptions(
to=[to], subject="Invoice attached", body="See attached.", attachments=attachment_ids
),
)
Java
public static SentEmailDto sendAttachment(ApiClient client, UUID inboxId, String to) throws ApiException {
// Upload the file first, then send its attachment ID with the email.
List<String> attachmentIds = new AttachmentControllerApi(client).uploadAttachment(new UploadAttachmentOptions()
.base64Contents(Base64.getEncoder().encodeToString("id,total\n1001,49.00\n".getBytes(StandardCharsets.UTF_8)))
.contentType("text/csv")
.filename("invoice.csv")).execute();
return new InboxControllerApi(client).sendEmailAndConfirm(inboxId, new SendEmailOptions()
.to(Collections.singletonList(to))
.subject("Invoice attached")
.body("See attached.")
.attachments(attachmentIds)).execute();
}
C#
public static SentEmailDto SendAttachment(Configuration configuration, Guid inboxId, string to)
{
// Upload the file first, then send its attachment ID with the email.
var attachmentIds = new AttachmentControllerApi(configuration).UploadAttachment(new UploadAttachmentOptions(
base64Contents: Convert.ToBase64String(Encoding.UTF8.GetBytes("id,total\n1001,49.00\n")),
contentType: "text/csv",
filename: "invoice.csv"));
return new InboxControllerApi(configuration).SendEmailAndConfirm(inboxId, new SendEmailOptions(
to: new List<string> { to }, subject: "Invoice attached", body: "See attached.",
attachments: attachmentIds));
}
Validating email recipients
You can verify recipients when sending emails:
Javascript
// send an email 5 seconds from now
await mailslurp.inboxController.sendWithSchedule({
inboxId: inbox.id,
sendAtNowPlusSeconds: 5,
validateBeforeEnqueue: true,
sendEmailOptions: {
to: [inbox.emailAddress],
subject: 'test-schedule-123',
body: '🌭',
filterBouncedRecipients: true,
validateEmailAddresses:
SendEmailOptionsValidateEmailAddressesEnum.VALIDATE_FILTER_REMOVE_INVALID,
},
});
See the verification guide for more options.
Use content templates

You can create email templates that support moustache style variables.
Javascript
const template = await mailslurp.templateController.createTemplate({
createTemplateOptions: {
name: 'Welcome email',
content: 'Hello {{firstName}}. Welcome to {{brandName}}.',
},
});
expect(template.id).toBeTruthy();
expect(template.variables).toEqual([
{
name: 'firstName',
variableType: TemplateVariableVariableTypeEnum.STRING,
},
{
name: 'brandName',
variableType: TemplateVariableVariableTypeEnum.STRING,
},
]);
Then send email using the template and pass variables for replacement.
Javascript
const templateObject = await mailslurp.templateController.getTemplate({
templateId,
});
expect(templateObject.content).toContain(
'Hello {{firstName}}. Welcome to {{brandName}}.'
);
const sent = await mailslurp.sendEmail(inboxId, {
to: [emailAddress],
subject: 'Welcome {{firstName}}',
template: templateId,
templateVariables: {
firstName: 'Sally',
brandName: 'My Company',
} as any,
});
Sending with schedule
You can send email with a delay or scheduled delivery time like so:
Javascript
// send an email 5 minutes in future using a date
const milliseconds = 5 * 60 * 1000;
const timeObject = new Date(new Date().getTime() + milliseconds);
await mailslurp.inboxController.sendWithSchedule({
inboxId: inbox.id,
sendAtTimestamp: timeObject,
validateBeforeEnqueue: true,
sendEmailOptions: {
to: [inbox.emailAddress],
subject: 'test-schedule-later',
body: '⏰',
filterBouncedRecipients: true,
},
});
Sending with queues
Use the sending queue to ensure emails are retried if they fail or your account experiences temporary limits.
Javascript
await mailslurp.inboxController.sendEmailWithQueue({
inboxId: inboxId,
sendEmailOptions: {
to: [recipient],
subject: 'Sent with a queue',
body:
'Use queues to allow recovery of failed email ' +
'sending when account reaches limits or has payment issues',
},
// validate before adding to queue to fail early
validateBeforeEnqueue: false,
});
Sending with SMTP/IMAP

Create an SMTP type inbox. Then use the IMAP or SMTP access details to access the inbox in code or from a mail client.
Javascript
// create an inbox using MailSlurp client
const mailslurp = new MailSlurp({ apiKey: process.env.API_KEY! });
const inbox = await mailslurp.createInboxWithOptions({
inboxType: CreateInboxDtoInboxTypeEnum.SMTP_INBOX,
});
// get smtp access details for mailbox
const server = await mailslurp.inboxController.getImapSmtpAccess({
inboxId: inbox.id,
});
// Create auth plain transport
const transport = nodemailer.createTransport({
host: server.smtpServerHost,
port: server.smtpServerPort,
secure: false,
auth: {
user: server.smtpUsername,
pass: server.smtpPassword,
type: 'PLAIN',
},
});
// Send email
const sent = await transport.sendMail({
from: inbox.emailAddress,
to: inbox.emailAddress,
subject: 'Test outbound email',
text: 'Can I send on behalf?',
html: '<b>Hello world</b>',
});
See the IMAP SMTP guide for more information.
Sent emails
Each sent email can be accessed with the SentEmail controller:
Javascript
const sentEmails = await mailslurp.sentController.getSentEmails({
inboxId: inbox.id,
});
expect(sentEmails!!.content!!.length).toBeDefined();
Delivery status
When emails are delivered an event is created. You can subscribe to delivery events using webhooks or view them in the dashboard.

Receiving emails
Inboxes receive emails. You can use the InboxController and EmailController to read email or use webhooks to have emails sent to your server directly.
Read emails in dashboard
The dashboard provides HTML previews for received emails:

Fetch emails in code
Emails are stored in the inbox that receives them. You can fetch emails directly using the inbox controller.
Javascript
const emails = await mailslurp.inboxController.getEmails({
inboxId: inbox.id,
unreadOnly: true,
});
expect(emails.length).toBeDefined();
To read one email in full, including its sender, subject, body and attachment IDs, get it by ID:
JavaScript
export async function getEmail(mailslurp, emailId) {
const email = await mailslurp.emailController.getEmail({ emailId });
return { from: email.from, subject: email.subject, body: email.body, attachments: email.attachments };
}
Python
def get_email(api_client, email_id):
email = mailslurp_client.EmailControllerApi(api_client).get_email(email_id)
return {"from": email._from, "subject": email.subject, "body": email.body,
"attachments": email.attachments}
Java
public static Email getEmail(ApiClient client, UUID emailId) throws ApiException {
Email email = new EmailControllerApi(client).getEmail(emailId).execute();
System.out.println(email.getFrom() + " " + email.getSubject());
return email;
}
C#
public static Email GetEmail(Configuration configuration, Guid emailId)
{
var email = new EmailControllerApi(configuration).GetEmail(emailId);
Console.WriteLine($"{email.From} {email.Subject}");
return email;
}
Use the email controller when you need the hydrated message body, browser preview URLs, or extracted links from an email.
/emails/{emailId}
Get hydrated email (headers and body)
Returns parsed email content including headers and body fields. Accessing hydrated content may mark the email as read depending on read-state rules.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | Email | OK |
HTTP examples
HTTP
GET /emails/00000000-0000-4000-8000-000000000000 HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json
cURL
Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
--request GET \
--url 'https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Accept: application/json' \
--output "$response_file" \
--write-out '%{http_code}')
case "$status" in
2??) mv "$response_file" 'response.json' ;;
*) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)
JavaScript (HTTP)
Requires Node.js 22+. Tested with Node.js 22.14.0.
import { writeFile } from "node:fs/promises";
const response = await fetch("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000", {
method: "GET",
headers: {
"x-api-key": "YOUR_API_KEY",
"Accept": "application/json"
},
redirect: "manual",
signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.json", responseBytes);
Python (HTTP)
Requires Python 3.9+. Tested with Python 3.9.21.
import http.client
from pathlib import Path
from urllib.parse import urlsplit
url = urlsplit("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000")
headers = {
"x-api-key": "YOUR_API_KEY",
"Accept": "application/json"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
path = (url.path or "/") + ("?" + url.query if url.query else "")
connection.request("GET", path, headers=headers)
response = connection.getresponse()
response_bytes = response.read()
if not 200 <= response.status < 300:
raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
Path("response.json").write_bytes(response_bytes)
finally:
connection.close()
/emails/{emailId}/links
Extract links from an email HTML body
Parses HTML content and extracts link URLs (`href`). For non-HTML emails this endpoint returns a validation error.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailId | string:uuid | Yes | ID of email to fetch text for |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
selector | string | No | Optional HTML query selector for links |
Responses
| Status | Schema | Description |
|---|---|---|
200 | EmailLinksResult | OK |
HTTP examples
HTTP
GET /emails/00000000-0000-4000-8000-000000000000/links HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: */*
cURL
Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
--request GET \
--url 'https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/links' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Accept: */*' \
--output "$response_file" \
--write-out '%{http_code}')
case "$status" in
2??) mv "$response_file" 'response.bin' ;;
*) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)
JavaScript (HTTP)
Requires Node.js 22+. Tested with Node.js 22.14.0.
import { writeFile } from "node:fs/promises";
const response = await fetch("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/links", {
method: "GET",
headers: {
"x-api-key": "YOUR_API_KEY",
"Accept": "*/*"
},
redirect: "manual",
signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);
Python (HTTP)
Requires Python 3.9+. Tested with Python 3.9.21.
import http.client
from pathlib import Path
from urllib.parse import urlsplit
url = urlsplit("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/links")
headers = {
"x-api-key": "YOUR_API_KEY",
"Accept": "*/*"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
path = (url.path or "/") + ("?" + url.query if url.query else "")
connection.request("GET", path, headers=headers)
response = connection.getresponse()
response_bytes = response.read()
if not 200 <= response.status < 300:
raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
Path("response.bin").write_bytes(response_bytes)
finally:
connection.close()
Get links and one-time codes from an email
MailSlurp parses the links and verification codes in each email, so tests can follow a sign-up link or enter a code without writing their own parser:
JavaScript
export async function linksAndCodes(mailslurp, emailId) {
// MailSlurp parses links and one-time codes from the email body for you.
const { links } = await mailslurp.emailController.getEmailLinks({ emailId });
const codes = await mailslurp.emailController.getEmailCodes({ emailId });
return { links, codes };
}
Python
def links_and_codes(api_client, email_id):
# MailSlurp parses links and one-time codes from the email body for you.
emails = mailslurp_client.EmailControllerApi(api_client)
links = emails.get_email_links(email_id).links
codes = emails.get_email_codes(email_id)
return links, codes
Java
public static List<String> linksAndCode(ApiClient client, UUID emailId) throws ApiException {
// MailSlurp parses links and one-time codes from the email body for you.
EmailControllerApi emails = new EmailControllerApi(client);
List<String> links = emails.getEmailLinks(emailId).execute().getLinks();
ExtractCodesResult codes = emails.getEmailCodes(emailId).execute();
if (Boolean.TRUE.equals(codes.getFound())) System.out.println("Code: " + codes.getCode());
return links;
}
C#
public static List<string> LinksAndCode(Configuration configuration, Guid emailId)
{
// MailSlurp parses links and one-time codes from the email body for you.
var emails = new EmailControllerApi(configuration);
var links = emails.GetEmailLinks(emailId).Links;
var codes = emails.GetEmailCodes(emailId);
if (codes.Found) Console.WriteLine($"Code: {codes.Code}");
return links;
}
Download attachments
Each email lists its attachment IDs. Download an attachment by ID to get its content type and bytes:
JavaScript
export async function downloadAttachment(mailslurp, emailId) {
const email = await mailslurp.emailController.getEmail({ emailId });
const attachmentId = email.attachments[0];
const file = await mailslurp.attachmentController.downloadAttachmentAsBase64Encoded({ attachmentId });
return { contentType: file.contentType, bytes: Buffer.from(file.base64FileContents, 'base64') };
}
Python
def download_attachment(api_client, email_id):
email = mailslurp_client.EmailControllerApi(api_client).get_email(email_id)
attachment_id = email.attachments[0]
file = mailslurp_client.AttachmentControllerApi(api_client).download_attachment_as_base64_encoded(
attachment_id
)
return file.content_type, base64.b64decode(file.base64_file_contents)
Java
public static byte[] downloadAttachment(ApiClient client, UUID emailId) throws ApiException {
Email email = new EmailControllerApi(client).getEmail(emailId).execute();
String attachmentId = email.getAttachments().get(0);
DownloadAttachmentDto file = new AttachmentControllerApi(client)
.downloadAttachmentAsBase64Encoded(attachmentId).execute();
return Base64.getDecoder().decode(file.getBase64FileContents());
}
C#
public static byte[] DownloadAttachment(Configuration configuration, Guid emailId)
{
var email = new EmailControllerApi(configuration).GetEmail(emailId);
var attachmentId = email.Attachments[0];
var file = new AttachmentControllerApi(configuration).DownloadAttachmentAsBase64Encoded(attachmentId);
return Convert.FromBase64String(file.Base64FileContents);
}
See the attachments page for more information.
Attachment downloads can be scoped to the email and attachment IDs, with byte and base64 variants available in the API reference.
/emails/{emailId}/attachments/{attachmentId}
Get email attachment bytes. Returned as `octet-stream` with content type header. If you have trouble with byte responses try the `downloadAttachmentBase64` response endpoints and convert the base 64 encoded content to a file or string.
Returns attachment bytes by attachment ID. Use attachment IDs from email payloads or attachment listing endpoints.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailId | string:uuid | Yes | ID of email |
attachmentId | string | Yes | ID of attachment |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
apiKey | string | No | Can pass apiKey in url for this request if you wish to download the file in a browser. Content type will be set to original content type of the attachment file. This is so that browsers can download the file correctly. |
Responses
| Status | Schema | Description |
|---|---|---|
default | string:byte | default response |
HTTP examples
HTTP
GET /emails/00000000-0000-4000-8000-000000000000/attachments/value HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: */*
cURL
Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
--request GET \
--url 'https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/attachments/value' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Accept: */*' \
--output "$response_file" \
--write-out '%{http_code}')
case "$status" in
2??) mv "$response_file" 'response.bin' ;;
*) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)
JavaScript (HTTP)
Requires Node.js 22+. Tested with Node.js 22.14.0.
import { writeFile } from "node:fs/promises";
const response = await fetch("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/attachments/value", {
method: "GET",
headers: {
"x-api-key": "YOUR_API_KEY",
"Accept": "*/*"
},
redirect: "manual",
signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);
Python (HTTP)
Requires Python 3.9+. Tested with Python 3.9.21.
import http.client
from pathlib import Path
from urllib.parse import urlsplit
url = urlsplit("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/attachments/value")
headers = {
"x-api-key": "YOUR_API_KEY",
"Accept": "*/*"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
path = (url.path or "/") + ("?" + url.query if url.query else "")
connection.request("GET", path, headers=headers)
response = connection.getresponse()
response_bytes = response.read()
if not 200 <= response.status < 300:
raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
Path("response.bin").write_bytes(response_bytes)
finally:
connection.close()
Reply to an email
A reply is sent from the inbox that received the email and keeps the original thread headers:
JavaScript
export async function reply(mailslurp, emailId) {
// Replies keep the original thread headers and send from the receiving inbox.
return mailslurp.emailController.replyToEmail({
emailId,
replyToEmailOptions: { body: 'Thanks, received.', isHTML: false },
});
}
Python
def reply(api_client, email_id):
# Replies keep the original thread headers and send from the receiving inbox.
return mailslurp_client.EmailControllerApi(api_client).reply_to_email(
email_id, mailslurp_client.ReplyToEmailOptions(body="Thanks, received.", is_html=False)
)
Java
public static SentEmailDto reply(ApiClient client, UUID emailId) throws ApiException {
// Replies keep the original thread headers and send from the receiving inbox.
return new EmailControllerApi(client).replyToEmail(emailId, new ReplyToEmailOptions()
.body("Thanks, received.")
.isHTML(false)).execute();
}
C#
public static SentEmailDto Reply(Configuration configuration, Guid emailId)
{
// Replies keep the original thread headers and send from the receiving inbox.
return new EmailControllerApi(configuration).ReplyToEmail(emailId,
new ReplyToEmailOptions(body: "Thanks, received.", isHTML: false));
}
Spam review

Every email is automatically scanned for viruses and spam ratings. You can access these on the email object.
Javascript
// fetch the email and review spam analysis
expect(email.analysis?.dkimVerdict).toEqual('PASS');
expect(email.analysis?.spamVerdict).toEqual('PASS');
// other verdicts available
expect(email.analysis?.dmarcVerdict).toBeDefined();
expect(email.analysis?.spfVerdict).toBeDefined();
expect(email.analysis?.virusVerdict).toBeDefined();
Wait for emails
The email wait for methods allow you to hold a request open until matching emails are found. This is very useful for receiving emails in tests when after you have performed an action.
Javascript
const user = await myApp.signUp(testInbox.emailAddress!);
// verify that confirmation email was sent by your app
const timeout = 30000;
const email = await mailslurp.waitForLatestEmail(testInbox.id, timeout);
// confirm the user using the code
const [_, verificationCode] = /your code is "([0-9]{6})"/g.exec(
email.body!
)!;
// do something with code like verifying an account
await myApp.confirmUser(verificationCode);
You can create complex search terms to match for email contents:
Javascript
const matchingEmails = await mailslurp.waitForMatchingEmails(
{
// match for emails with no attachments
conditions: [
{
condition: ConditionOptionConditionEnum.HAS_ATTACHMENTS,
value: ConditionOptionValueEnum.FALSE,
},
],
// match for emails from a specific email address
matches: [
{
field: MatchOptionFieldEnum.FROM,
should: MatchOptionShouldEnum.CONTAIN,
value: inbox.emailAddress,
},
],
},
1,
inbox.id,
timeout,
unreadOnly
);
Receive email with webhooks
The best way to receive emails at scale is by using webhooks.
Javascript
await mailslurp.webhookController.createWebhook({
inboxId: inbox.id,
createWebhookOptions: {
eventName: CreateWebhookOptionsEventNameEnum.NEW_EMAIL,
url: slackIncomingWebhookUrl,
// custom request body for slack uses {{subject}} to insert
// the subject from the standard NEW_EMAIL payload
requestBodyTemplate: `{"text":"New message: {{subject}}"}`,
},
});
Receive emails from connectors
If you have connected a 3rd party email account with MailSlurp inbox connectors you can synchronize emails between them using the connector controller. Emails are also synchronized during wait for methods and if you pass a syncConnectors argument to fetch email commands. This means MailSlurp will pull new emails from your external mailbox before returning results.
Test email content
MailSlurp provides many features for testing the rendering, validity, and client-support of email content. You can use MailSlurp to check spam ratings, DKIM/DMARC/SPF records, CSS/HTML feature support, cross-device rendering, broken links and more.
Content checks can run directly against the hydrated email body. Use regex matching for OTP extraction, content-part reads for multipart messages, and preview URLs when a browser-rendered view is useful.
/emails/{emailId}/contentMatch
Run regex against hydrated email body and return matches
Executes a Java regex pattern over hydrated email body text and returns the full match plus capture groups. Pattern syntax follows Java `Pattern` rules.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailId | string:uuid | Yes | ID of email to match against |
Request body (required)
| Field | Type | Required | Description |
|---|---|---|---|
pattern | string | Yes | Java style regex pattern. Do not include the typical `/` at start or end of regex in some languages. Given an example `your code is: 12345` the pattern to extract match looks like `code is: (\d{6})`. This will return an array of matches with the first matching the entire pattern and the subsequent matching the groups: `['code is: 123456', '123456']` See https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html for more information of available patterns. |
{
"pattern": "value"
}
Responses
| Status | Schema | Description |
|---|---|---|
200 | EmailContentMatchResult | OK |
HTTP examples
HTTP
POST /emails/00000000-0000-4000-8000-000000000000/contentMatch HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Content-Type: application/json
Accept: */*
{
"pattern": "value"
}
cURL
Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.
(
set -eu
response_file=$(mktemp)
request_body=$(mktemp)
trap 'rm -f "$response_file" "$request_body"' EXIT
{
printf '%b' '{\0012 "pattern": "value"\0012}'
} > "$request_body"
status=$(curl --silent --show-error \
--request POST \
--url 'https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/contentMatch' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--header 'Accept: */*' \
--output "$response_file" \
--write-out '%{http_code}' \
--data-binary "@$request_body")
case "$status" in
2??) mv "$response_file" 'response.bin' ;;
*) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)
JavaScript (HTTP)
Requires Node.js 22+. Tested with Node.js 22.14.0.
import { writeFile } from "node:fs/promises";
const body = Buffer.concat([
Buffer.from("{\n \"pattern\": \"value\"\n}", "utf8")
]);
const response = await fetch("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/contentMatch", {
method: "POST",
headers: {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
"Accept": "*/*"
},
body,
redirect: "manual",
signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);
Python (HTTP)
Requires Python 3.9+. Tested with Python 3.9.21.
import http.client
from pathlib import Path
from urllib.parse import urlsplit
url = urlsplit("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/contentMatch")
headers = {
"x-api-key": "YOUR_API_KEY",
"Content-Type": "application/json",
"Accept": "*/*"
}
body = b"".join([
"{\n \"pattern\": \"value\"\n}".encode("utf-8")
])
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
path = (url.path or "/") + ("?" + url.query if url.query else "")
connection.request("POST", path, body=body, headers=headers)
response = connection.getresponse()
response_bytes = response.read()
if not 200 <= response.status < 300:
raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
Path("response.bin").write_bytes(response_bytes)
finally:
connection.close()
/emails/{emailId}/contentPart
Get email content part by content type
Extracts one MIME body part by `contentType` and optional `index`, returned in a structured DTO with metadata.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailId | string:uuid | Yes | ID of email to match against |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
contentType | string | Yes | Content type |
strict | boolean | No | Strict content type match |
index | integer:int32 | No | Index of content type part if multiple |
Responses
| Status | Schema | Description |
|---|---|---|
200 | EmailContentPartResult | OK |
HTTP examples
HTTP
GET /emails/00000000-0000-4000-8000-000000000000/contentPart?contentType=value HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: application/json;charset=UTF-8
cURL
Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
--request GET \
--url 'https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/contentPart?contentType=value' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Accept: application/json;charset=UTF-8' \
--output "$response_file" \
--write-out '%{http_code}')
case "$status" in
2??) mv "$response_file" 'response.json' ;;
*) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)
JavaScript (HTTP)
Requires Node.js 22+. Tested with Node.js 22.14.0.
import { writeFile } from "node:fs/promises";
const response = await fetch("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/contentPart?contentType=value", {
method: "GET",
headers: {
"x-api-key": "YOUR_API_KEY",
"Accept": "application/json;charset=UTF-8"
},
redirect: "manual",
signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.json", responseBytes);
Python (HTTP)
Requires Python 3.9+. Tested with Python 3.9.21.
import http.client
from pathlib import Path
from urllib.parse import urlsplit
url = urlsplit("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/contentPart?contentType=value")
headers = {
"x-api-key": "YOUR_API_KEY",
"Accept": "application/json;charset=UTF-8"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
path = (url.path or "/") + ("?" + url.query if url.query else "")
connection.request("GET", path, headers=headers)
response = connection.getresponse()
response_bytes = response.read()
if not 200 <= response.status < 300:
raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
Path("response.json").write_bytes(response_bytes)
finally:
connection.close()
/emails/{emailId}/urls
Get email URLs for viewing in browser or downloading
Returns precomputed URLs for preview and raw message access for the specified email.
Request, parameters, and responses
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
emailId | string:uuid | Yes |
Responses
| Status | Schema | Description |
|---|---|---|
200 | EmailPreviewUrls | OK |
HTTP examples
HTTP
GET /emails/00000000-0000-4000-8000-000000000000/urls HTTP/1.1
Host: api.mailslurp.com
x-api-key: YOUR_API_KEY
Accept: */*
cURL
Requires cURL 7.76+ and a POSIX shell. Tested with cURL 8.12.1.
(
set -eu
response_file=$(mktemp)
trap 'rm -f "$response_file"' EXIT
status=$(curl --silent --show-error \
--request GET \
--url 'https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/urls' \
--header 'x-api-key: YOUR_API_KEY' \
--header 'Accept: */*' \
--output "$response_file" \
--write-out '%{http_code}')
case "$status" in
2??) mv "$response_file" 'response.bin' ;;
*) printf 'HTTP %s\n' "$status" >&2; cat "$response_file" >&2; exit 1 ;;
esac
)
JavaScript (HTTP)
Requires Node.js 22+. Tested with Node.js 22.14.0.
import { writeFile } from "node:fs/promises";
const response = await fetch("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/urls", {
method: "GET",
headers: {
"x-api-key": "YOUR_API_KEY",
"Accept": "*/*"
},
redirect: "manual",
signal: AbortSignal.timeout(60000),
});
const responseBytes = Buffer.from(await response.arrayBuffer());
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${responseBytes.toString("utf8")}`);
}
await writeFile("response.bin", responseBytes);
Python (HTTP)
Requires Python 3.9+. Tested with Python 3.9.21.
import http.client
from pathlib import Path
from urllib.parse import urlsplit
url = urlsplit("https://api.mailslurp.com/emails/00000000-0000-4000-8000-000000000000/urls")
headers = {
"x-api-key": "YOUR_API_KEY",
"Accept": "*/*"
}
connection_class = http.client.HTTPSConnection if url.scheme == "https" else http.client.HTTPConnection
connection = connection_class(url.hostname, url.port, timeout=60)
try:
path = (url.path or "/") + ("?" + url.query if url.query else "")
connection.request("GET", path, headers=headers)
response = connection.getresponse()
response_bytes = response.read()
if not 200 <= response.status < 300:
raise RuntimeError(f"HTTP {response.status}: {response_bytes.decode('utf-8', errors='replace')}")
Path("response.bin").write_bytes(response_bytes)
finally:
connection.close()
Running this code needs an API key. Get one free