Forwarding
Forwarding
Inbox forwarding allows you to create rules that match inbound emails and forward them automatically to other email addresses.
Quick links
Find forwarders in dashboard
You can create and manage inbox forwarders in the MailSlurp dashboard or using the API.
1. Click inboxes
2. Click forwarders
3. Or access via the inbox pageHow forwarding works
Inbox forwarding rules can be attached to inboxes and catch-all inboxes and are applied to inbound emails. Rules can match on email fields such as subject, or sender, and can be used to forward emails to other email addresses.
When an inbox with a forwarding rule attached receives an inbound email the rules are evaluated. For each matching rule the email is forwarded to the attached rule recipient. Both the original inbox and the recipient inbox receive the inbound email.
Creating inbox forwarders
You can create inbox forwarders in the dashboard or using the API.

Matching inbound emails
You can create rules to match on a variety of email properties:
const forwarderFields = [ CreateInboxForwarderOptionsFieldEnum.SENDER, CreateInboxForwarderOptionsFieldEnum.RECIPIENTS, CreateInboxForwarderOptionsFieldEnum.ATTACHMENTS, CreateInboxForwarderOptionsFieldEnum.SUBJECT]At minimum, provide:
- one match strategy (
field+match, ormatchOptions), and - one or more
forwardToRecipients.
To create a basic forwarder in code:
await mailslurp.inboxForwarderController.createNewInboxForwarder({ inboxId: inbox2.id, createInboxForwarderOptions: { field: CreateInboxForwarderOptionsFieldEnum.SENDER, match: inbox1.emailAddress!, forwardToRecipients: [inbox3.emailAddress!], },});This pattern is ideal for simple mailbox workflows where one condition controls one destination list.
You can use should to control how matching is done:
WILDCARD: wildcard matching such asInvoice*.MATCH: regex matching.CONTAIN: case-insensitive contains.EQUAL: normalized equality.
CONTAIN and EQUAL examples
Use CONTAIN for partial string matching and EQUAL for exact normalized matches.
await inboxForwarderController.createNewInboxForwarder({ inboxId, createInboxForwarderOptions: { field: 'SUBJECT', should: 'CONTAIN', match: 'security alert', forwardToRecipients: ['ops@example.com'], },});
await inboxForwarderController.createNewInboxForwarder({ inboxId, createInboxForwarderOptions: { field: 'SENDER', should: 'EQUAL', match: 'billing@example.com', forwardToRecipients: ['finance@example.com'], },});Use CONTAIN when subjects may include prefixes/suffixes (for example timestamps). Use EQUAL when sender identity must be exact.
Wildcard matching
You can use an * asterisk to match all characters after a given pattern.
await mailslurp.inboxForwarderController.createNewInboxForwarder({ inboxId: inbox1.id, createInboxForwarderOptions: { field: CreateInboxForwarderOptionsFieldEnum.SUBJECT, match: 'Invoice AB-*', forwardToRecipients: [inbox2.emailAddress!], },});Test the wildcard rule by sending an email and waiting for the forwarded copy:
const sent = await mailslurp.inboxController.sendEmailAndConfirm({ inboxId: inbox3.id!!, sendEmailOptions: { to: [inbox1.emailAddress!!], subject: 'Invoice AB-123', },});// see that inbox1 gets the original emailconst receivedEmail = await mailslurp.waitController.waitForLatestEmail({ inboxId: inbox1.id, timeout: 60000, unreadOnly: true,});expect(receivedEmail.subject).toContain('Invoice AB-123');
// see that inbox2 also gets a forwarded emailconst forwardedEmail = await mailslurp.waitForLatestEmail( inbox2.id, 60000, true);expect(forwardedEmail.subject).toContain('Invoice AB-123');This is a good fit when you have stable prefixes like Invoice*, Alert*, or ticket patterns where strict regex is unnecessary.
Regex pattern matching (should=MATCH)
Use regex when you need strict shape validation (for example OTP formats):
const patternForwarder = await forwarderController.createNewInboxForwarder({ inboxId: sourceInbox.id, createInboxForwarderOptions: { field: 'SUBJECT', should: 'MATCH', match: '^OTP code [0-9]{6}$', forwardToRecipients: [destinationInbox.emailAddress!], },});await inboxController.sendEmailAndConfirm({ inboxId: destinationInbox.id!, sendEmailOptions: { to: [sourceInbox.emailAddress!], subject: 'OTP code 654321', body: 'verification', },});const forwardedEmail = await waitController.waitForLatestEmail({ inboxId: destinationInbox.id!, timeout: 60_000, unreadOnly: true,});const patternSuccessEvent = await waitForForwarderSuccessEvent( patternForwarder.id!,);Anchor regexes with ^ and $ when you want full-value matching and avoid unintended partial matches.
Combined rules with nested AND / OR
You can combine:
- a simple top-level
field+match+shouldrule, and matchOptionsfor nested boolean logic.
Both must match when provided together.
const combinedForwarder = await forwarderController.createNewInboxForwarder( { inboxId: sourceInbox.id, createInboxForwarderOptions: { field: 'SUBJECT', should: 'CONTAIN', match: 'alert', forwardToRecipients: [destinationInbox.emailAddress!], matchOptions: { operator: 'AND', matches: [ { field: 'SENDER', should: 'EQUAL', value: destinationInbox.emailAddress!, }, ], groups: [ { operator: 'OR', matches: [ { field: 'SUBJECT', should: 'CONTAIN', value: 'critical' }, { field: 'SUBJECT', should: 'CONTAIN', value: 'warning' }, ], }, ], }, }, },);await inboxController.sendEmailAndConfirm({ inboxId: destinationInbox.id!, sendEmailOptions: { to: [sourceInbox.emailAddress!], subject: 'critical alert: cpu high', body: 'threshold exceeded', },});const forwardedEmail = await waitController.waitForLatestEmail({ inboxId: destinationInbox.id!, timeout: 60_000, unreadOnly: true,});const combinedSuccessEvent = await waitForForwarderSuccessEvent( combinedForwarder.id!,);Use this for production triage flows where one weak signal is not enough, such as sender + keyword + one-of category checks.
Attachment-aware forwarding
Forwarders support attachment-aware fields:
ATTACHMENT_FILENAME: match on attachment names.ATTACHMENT_TEXT: extract attachment text and match on extracted content.
Attachment filename matching
Use ATTACHMENT_FILENAME when filename itself is enough.
await inboxForwarderController.createNewInboxForwarder({ inboxId, createInboxForwarderOptions: { field: 'ATTACHMENT_FILENAME', should: 'MATCH', match: '.*\\.pdf$', forwardToRecipients: ['archive@example.com'], },});This is useful for deterministic document routing when filenames are generated by upstream systems.
For ATTACHMENT_TEXT, you can set attachmentTextExtractionMethod:
AUTONATIVE(default)OCRLLMOCR_THEN_LLM
await inboxForwarderController.createNewInboxForwarder({ inboxId, createInboxForwarderOptions: { field: 'ATTACHMENT_TEXT', should: 'CONTAIN', match: 'order-991', forwardToRecipients: ['ops@example.com'], attachmentTextExtractionMethod: 'OCR_THEN_LLM', },});Recommended baseline:
- start with
NATIVEfor machine-readable text files and PDFs, - move to
OCRfor image-heavy scans, - use
LLMorOCR_THEN_LLMfor complex layouts and semi-structured docs.
Attachment text matching with native extraction
This flow is deterministic and usually fastest for plain text attachments and text-first PDFs.
const attachmentTextForwarder = await forwarderController.createNewInboxForwarder({ inboxId: sourceInbox.id, createInboxForwarderOptions: { field: 'ATTACHMENT_TEXT', should: 'CONTAIN', match: 'invoice-7788', forwardToRecipients: [destinationInbox.emailAddress!], attachmentTextExtractionMethod: 'NATIVE', } as any, });await inboxController.sendEmailAndConfirm({ inboxId: destinationInbox.id!, sendEmailOptions: { to: [sourceInbox.emailAddress!], subject: 'Invoice attached', body: 'Please see attachment', attachments: attachmentIds, },});const forwardedEmail = await waitController.waitForLatestEmail({ inboxId: destinationInbox.id!, timeout: 60_000, unreadOnly: true,});const attachmentTextSuccessEvent = await waitForForwarderSuccessEvent( attachmentTextForwarder.id!,);AI/LLM-based attachment matching
If your plan includes AI features, use attachmentTextExtractionMethod: 'LLM' for harder documents.
const aiMatchForwarder = await forwarderController.createNewInboxForwarder({ inboxId: sourceInbox.id, createInboxForwarderOptions: { field: 'ATTACHMENT_TEXT', should: 'CONTAIN', match: 'llm-forward-key-42', forwardToRecipients: [destinationInbox.emailAddress!], attachmentTextExtractionMethod: 'LLM', } as any,});await inboxController.sendEmailAndConfirm({ inboxId: destinationInbox.id!, sendEmailOptions: { to: [sourceInbox.emailAddress!], subject: 'LLM extraction check', body: 'Use AI extraction for this attachment', attachments: attachmentIds, },});const forwardedEmail = await waitController.waitForLatestEmail({ inboxId: destinationInbox.id!, timeout: 90_000, unreadOnly: true,});const aiMatchSuccessEvent = await waitForForwarderSuccessEvent( aiMatchForwarder.id!,);LLM extraction is best for noisy or irregular documents. It may add latency and token-based costs compared with native extraction.
Non-match behavior
When an email does not match a forwarder rule:
- no forwarded email is sent, and
- no
SUCCESSforwarder event is recorded for that email.
const nonMatchForwarder = await forwarderController.createNewInboxForwarder( { inboxId: sourceInbox.id, createInboxForwarderOptions: { field: 'SUBJECT', should: 'MATCH', match: '^invoice [0-9]{4}$', forwardToRecipients: [destinationInbox.emailAddress!], }, },);await inboxController.sendEmailAndConfirm({ inboxId: destinationInbox.id!, sendEmailOptions: { to: [sourceInbox.emailAddress!], subject: 'not-an-invoice-subject', body: 'should not forward', },});const events = await forwarderController.getInboxForwarderEvents({ id: nonMatchForwarder.id!,});Including negative tests prevents silent over-forwarding and helps validate that your matching logic is specific enough.
Tracking forwarding events
Each forwarding event is recorded and can be accessed via API or dashboard. Use events to audit match behavior, measure forwarding volume, and troubleshoot rules.
Forwarder events include:
- status (
SUCCESSorFAILURE), - related IDs (for example
emailId,sentId,forwarderId,inboxId), - timestamp and optional message details.
Recommended event workflow:
- After sending a test message, poll forwarder events by
forwarderId. - Verify at least one
SUCCESSevent for matched scenarios. - For failures, inspect the event message and then verify recipient addresses and account sending permissions.
- For negative tests, confirm no
SUCCESSevents are created for non-matching messages.
Event checks are especially important when using nested matchOptions or attachment text extraction, where false positives are expensive.
Advanced examples
Here is an example of forwarding between inboxes.
const mailslurp = new MailSlurp({ apiKey: process.env.apiKey });// create two inboxes for testingconst inbox1 = await mailslurp.inboxController.createInboxWithDefaults();const inbox2 = await mailslurp.inboxController.createInboxWithDefaults();const inbox3 = await mailslurp.inboxController.createInboxWithDefaults();
// add auto forwarding rule to inbox 2await mailslurp.inboxForwarderController.createNewInboxForwarder({ // attach rule to inbox 2 inboxId: inbox2.id, createInboxForwarderOptions: { // filter emails that match the sender from inbox 1 and send to inbox 3 field: CreateInboxForwarderOptionsFieldEnum.SENDER, match: inbox1.emailAddress, forwardToRecipients: [inbox3.emailAddress], },});
// send email from inbox1 to inbox2await mailslurp.sendEmail(inbox1.id!!, { to: [inbox2.emailAddress!!], subject: 'Hello',});
// see that inbox2 gets the original emailconst receivedEmail = await mailslurp.waitForLatestEmail( inbox2.id, 60000, true);expect(receivedEmail.subject).toContain('Hello');
// see that inbox3 gets a forwarded emailconst forwardedEmail = await mailslurp.waitForLatestEmail( inbox3.id, 60000, true);expect(forwardedEmail.subject).toContain('Hello');
// check the sent messages for inbox2 to find the forwarded messageconst sentFromInbox2 = await mailslurp.sentController.getSentEmails({ inboxId: inbox2.id,});expect(sentFromInbox2.totalElements).toEqual(1);const forwardedMessage = sentFromInbox2.content[0];expect(forwardedMessage.to).toEqual([inbox3.emailAddress]);expect(forwardedMessage.from).toEqual(inbox2.emailAddress);Other resources
You may also be interested in webhooks, rulesets, and auto-replies.