Postman can run a complete MailSlurp email receive workflow without an SDK. Create an inbox, store its ID and email address as collection variables, trigger your application or external service, wait until a response email matches the subject token you expect, then verify and download the attachment.


[![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/20377432-d2de26c9-419b-4f5d-a26e-459d8405b58d?action=collection%2Ffork&source=rip_markdown&collection-url=entityId%3D20377432-d2de26c9-419b-4f5d-a26e-459d8405b58d%26entityType%3Dcollection%26workspaceId%3D6fac3a62-259f-4f27-924e-8b53b54e31e8#?env%5BProduction%5D=W3sia2V5IjoiYmFzZVVybCIsInZhbHVlIjoiaHR0cHM6Ly9hcGkubWFpbHNsdXJwLmNvbSIsImVuYWJsZWQiOnRydWUsInR5cGUiOiJkZWZhdWx0Iiwic2Vzc2lvblZhbHVlIjoiaHR0cHM6Ly9hcGkubWFpbHNsdXJwLmNvbSIsImNvbXBsZXRlU2Vzc2lvblZhbHVlIjoiaHR0cHM6Ly9hcGkubWFpbHNsdXJwLmNvbSIsInNlc3Npb25JbmRleCI6MH0seyJrZXkiOiJhcGlLZXkiLCJ2YWx1ZSI6IiIsImVuYWJsZWQiOnRydWUsInR5cGUiOiJzZWNyZXQiLCJzZXNzaW9uVmFsdWUiOiIiLCJjb21wbGV0ZVNlc3Npb25WYWx1ZSI6IiIsInNlc3Npb25JbmRleCI6MX1d)


The companion Postman collection includes the same variables, `X-API-Key` authentication, pre-request scripts, Tests tab assertions, subject matching, attachment metadata checks, and download requests shown below. You can also [open the public collection in Postman](https://www.postman.com/mailslurp-api/mailslurp-email-api/collection/unhrsx5/reading-email-in-postman) to inspect each request before forking it.

The same REST sequence works in ACCELQ and other API automation tools because each step is a normal HTTPS request authenticated with the `X-API-Key` header.

```mermaid
sequenceDiagram
  autonumber
  participant Runner as Postman or ACCELQ
  participant MailSlurp as MailSlurp REST API
  participant Inbox as MailSlurp inbox
  participant App as External service

  Runner->>MailSlurp: POST /inboxes/withDefaults
  MailSlurp-->>Runner: inboxId and emailAddress
  Runner->>Runner: Store inboxId, inboxAddress, subjectToken
  Runner->>MailSlurp: POST /sendEmail with senderId inboxId
  MailSlurp->>App: Email from created inbox address
  App->>Inbox: Reply with subject containing 8 digit token and attachment
  Runner->>MailSlurp: POST /waitForMatchingFirstEmail
  MailSlurp-->>Runner: Matched email with attachment IDs
  Runner->>MailSlurp: GET attachment metadata
  MailSlurp-->>Runner: name, contentType, contentLength
  Runner->>MailSlurp: GET attachment bytes or base64
  MailSlurp-->>Runner: Downloaded attachment
```

## How MailSlurp fits the flow

A MailSlurp inbox is a real email address controlled by the API. When you create an inbox, MailSlurp returns an `id` and an `emailAddress`. Use the `id` for API calls and the `emailAddress` anywhere a sender or receiver needs a real address.

For the scenario described:

1. Create a new inbox for the test run.
2. Save `id` as `inboxId` and `emailAddress` as `inboxAddress` in Postman.
3. Send from that inbox by passing `senderId: "{{inboxId}}"`, or trigger your own external service to send to `{{inboxAddress}}`.
4. Include an 8 digit token in the subject, such as `Postman attachment response 48291357`.
5. Wait for the reply with `waitForMatchingFirstEmail`.
6. Verify attachment metadata with the email attachment endpoints.
7. Download the attachment as bytes, or use the base64 endpoint for automated runners.

If the receiver should see the exact mailbox you created, make sure the send request uses `senderId` set to the created inbox ID. The `From` address will be the inbox email address returned by MailSlurp. If you need a specific human-readable address, create the inbox on a verified domain and keep the same `senderId` pattern.

## Postman setup

Create a Postman collection and add these collection variables:

| Variable                        | Example                          | Purpose                               |
| ------------------------------- | -------------------------------- | ------------------------------------- |
| `baseUrl`                       | `https://api.mailslurp.com`      | MailSlurp REST API base URL           |
| `apiKey`                        | `YOUR_MAILSLURP_API_KEY`         | API key from the MailSlurp dashboard  |
| `inboxId`                       | empty                            | Set after inbox creation              |
| `inboxAddress`                  | empty                            | Set after inbox creation              |
| `externalRecipient`             | `service-under-test@example.com` | Address that receives the first email |
| `subjectToken`                  | empty                            | Generated 8 digit token               |
| `expectedSubject`               | empty                            | Subject used for send and match       |
| `expectedAttachmentName`        | `report.pdf`                     | Optional metadata assertion           |
| `expectedAttachmentContentType` | `application/pdf`                | Optional metadata assertion           |
| `emailId`                       | empty                            | Set after wait-for-match              |
| `attachmentId`                  | empty                            | Set after metadata lookup             |

The companion collection uses `baseUrl` for portability. The request snippets below spell out `https://api.mailslurp.com` so each call is clear when copied into Postman, Newman, ACCELQ, or another HTTP runner.

Get an API key from the MailSlurp dashboard, then authenticate every request with this header:

```http
X-API-Key: {{apiKey}}
```

In Postman, set the header at collection level so every request inherits it. Header names are case-insensitive, so `x-api-key` and `X-API-Key` both work.

## 1. Create an inbox

Use the default inbox endpoint when you want a unique address for each run.



{{LANDING_SHORTCODE:API_ENDPOINT:%7B%22operationId%22%3A%22createInboxWithDefaults%22%7D}}



Postman request:

```http
POST https://api.mailslurp.com/inboxes/withDefaults
X-API-Key: {{apiKey}}
```

Add this to the request's Tests tab:

```javascript
const inbox = pm.response.json();

pm.test("created a MailSlurp inbox", () => {
  pm.response.to.have.status(201);
  pm.expect(inbox.id).to.be.a("string");
  pm.expect(inbox.emailAddress).to.include("@");
});

pm.collectionVariables.set("inboxId", inbox.id);
pm.collectionVariables.set("inboxAddress", inbox.emailAddress);

const token = String(Math.floor(10000000 + Math.random() * 90000000));
pm.collectionVariables.set("subjectToken", token);
pm.collectionVariables.set("expectedSubject", `Postman attachment response ${token}`);
```

After this request, Postman can reuse `{{inboxId}}`, `{{inboxAddress}}`, `{{subjectToken}}`, and `{{expectedSubject}}` in later calls.

## 2. Send or trigger the email

If your test starts by sending an email from the newly created mailbox to another system, call the MailSlurp send endpoint and pass the created inbox as `senderId`.



{{LANDING_SHORTCODE:API_ENDPOINT:%7B%22operationId%22%3A%22sendEmailSimple%22%7D}}



Postman request:

```http
POST https://api.mailslurp.com/sendEmail
X-API-Key: {{apiKey}}
Content-Type: application/json
```

Body:

```json
{
  "senderId": "{{inboxId}}",
  "to": "{{externalRecipient}}",
  "subject": "{{expectedSubject}}",
  "body": "Please reply to {{inboxAddress}} with the requested attachment. Token: {{subjectToken}}"
}
```

This sends from the MailSlurp inbox you just created. The receiver sees the created inbox address as the sender.

If your application is the sender, call your application endpoint instead and pass `{{inboxAddress}}` as the recipient. For example:

```http
POST {{appBaseUrl}}/send-report
Content-Type: application/json
```

```json
{
  "to": "{{inboxAddress}}",
  "subject": "{{expectedSubject}}",
  "includeAttachment": true
}
```

The important detail is that the response email should arrive at `{{inboxAddress}}` and its subject should contain `{{subjectToken}}`.

## 3. Wait for the matching reply

For a subject that contains 8 random digits, use `waitForMatchingFirstEmail`. It holds the request open until a matching email arrives or the timeout expires. This is more reliable than manually polling a list endpoint.



{{LANDING_SHORTCODE:API_ENDPOINT:%7B%22operationId%22%3A%22waitForMatchingFirstEmail%22%7D}}



Postman request:

```http
POST https://api.mailslurp.com/waitForMatchingFirstEmail?inboxId={{inboxId}}&timeout=120000&unreadOnly=true
X-API-Key: {{apiKey}}
Content-Type: application/json
```

Body:

```json
{
  "matches": [
    {
      "field": "SUBJECT",
      "should": "CONTAIN",
      "value": "{{subjectToken}}"
    }
  ],
  "conditions": [
    {
      "condition": "HAS_ATTACHMENTS",
      "value": "TRUE"
    }
  ]
}
```

Add this to the Tests tab:

```javascript
const email = pm.response.json();
const subjectToken = pm.collectionVariables.get("subjectToken");
const attachments = email.attachments || [];

pm.test("matched the expected response email", () => {
  pm.response.to.have.status(200);
  pm.expect(email.id).to.be.a("string");
  pm.expect(email.subject || "").to.include(subjectToken);
});

pm.test("response email has at least one attachment", () => {
  pm.expect(attachments.length).to.be.greaterThan(0);
});

pm.collectionVariables.set("emailId", email.id);
pm.collectionVariables.set("attachmentId", attachments[0]);
```

Use `unreadOnly=true` for repeatable test runs. It prevents an older email in the same inbox from satisfying the wait.

### Optional latest-email fallback

If you do not know the subject in advance, use `waitForLatestEmail` and then assert on the returned message.



{{LANDING_SHORTCODE:API_ENDPOINT:%7B%22operationId%22%3A%22waitForLatestEmail%22%7D}}



```http
GET https://api.mailslurp.com/waitForLatestEmail?inboxId={{inboxId}}&timeout=120000&unreadOnly=true
X-API-Key: {{apiKey}}
```

This is useful for exploratory Postman work, but subject matching is better for automated suites because it ties the assertion to the current run.

## 4. Verify attachment name and file type

The email returned by the wait endpoint includes attachment IDs. Use the attachment metadata endpoints to verify the file name, MIME type, and size before downloading the content.

To list metadata for all attachments on the email:



{{LANDING_SHORTCODE:API_ENDPOINT:%7B%22operationId%22%3A%22getEmailAttachments%22%7D}}



```http
GET https://api.mailslurp.com/emails/{{emailId}}/attachments
X-API-Key: {{apiKey}}
```

Add this to the Tests tab:

```javascript
const attachments = pm.response.json();
const expectedName = pm.collectionVariables.get("expectedAttachmentName");
const expectedContentType = pm.collectionVariables.get("expectedAttachmentContentType");
const target = expectedName
  ? attachments.find((attachment) => attachment.name === expectedName)
  : attachments[0];

pm.test("found attachment metadata", () => {
  pm.response.to.have.status(200);
  pm.expect(target, "matching attachment").to.exist;
  pm.expect(target.id).to.be.a("string");
  pm.expect(target.name).to.be.a("string");
  pm.expect(target.contentType).to.be.a("string");
  pm.expect(target.contentLength).to.be.greaterThan(0);
});

if (expectedName) {
  pm.test("attachment name matches", () => {
    pm.expect(target.name).to.eql(expectedName);
  });
}

if (expectedContentType) {
  pm.test("attachment content type matches", () => {
    pm.expect(target.contentType).to.eql(expectedContentType);
  });
}

pm.collectionVariables.set("attachmentId", target.id);
pm.collectionVariables.set("attachmentName", target.name);
pm.collectionVariables.set("attachmentContentType", target.contentType);
```

To fetch metadata for one attachment ID:



{{LANDING_SHORTCODE:API_ENDPOINT:%7B%22operationId%22%3A%22getAttachmentMetaData%22%7D}}



```http
GET https://api.mailslurp.com/emails/{{emailId}}/attachments/{{attachmentId}}/metadata
X-API-Key: {{apiKey}}
```

This endpoint returns fields such as `name`, `contentType`, `contentLength`, and `id`. Use it when your previous step already selected the attachment ID.

## 5. Download the attachment

For manual Postman testing, request the binary attachment endpoint and use Postman's Send and Download action.



{{LANDING_SHORTCODE:API_ENDPOINT:%7B%22operationId%22%3A%22downloadAttachment%22%7D}}



```http
GET https://api.mailslurp.com/emails/{{emailId}}/attachments/{{attachmentId}}
X-API-Key: {{apiKey}}
Accept: application/octet-stream
```

Add a lightweight response check:

```javascript
const expectedContentType = pm.collectionVariables.get("attachmentContentType");
const responseType = pm.response.headers.get("Content-Type") || "";

pm.test("download response is successful", () => {
  pm.response.to.have.status(200);
});

if (expectedContentType) {
  pm.test("downloaded file type matches metadata", () => {
    pm.expect(responseType).to.include(expectedContentType);
  });
}
```

For automated runners, the base64 endpoint is often easier because the response is JSON and can be decoded by Newman, ACCELQ, a CI script, or a downstream API step.



{{LANDING_SHORTCODE:API_ENDPOINT:%7B%22operationId%22%3A%22downloadAttachmentBase64%22%7D}}



```http
GET https://api.mailslurp.com/emails/{{emailId}}/attachments/{{attachmentId}}/base64
X-API-Key: {{apiKey}}
```

Tests tab:

```javascript
const attachment = pm.response.json();
const expectedContentType = pm.collectionVariables.get("attachmentContentType");

pm.test("downloaded base64 attachment", () => {
  pm.response.to.have.status(200);
  pm.expect(attachment.base64FileContents).to.be.a("string").and.not.empty;
  pm.expect(attachment.sizeBytes).to.be.greaterThan(0);
});

if (expectedContentType) {
  pm.test("base64 file type matches metadata", () => {
    pm.expect(attachment.contentType).to.eql(expectedContentType);
  });
}

pm.collectionVariables.set("attachmentBase64", attachment.base64FileContents);
```

## Running the same flow in ACCELQ

ACCELQ can use the same MailSlurp REST calls as Postman:

1. Add `X-API-Key: <your API key>` to each MailSlurp API step.
2. Store `id` and `emailAddress` from `POST /inboxes/withDefaults` as scenario variables.
3. Call your application or `POST /sendEmail` with those variables.
4. Use `POST /waitForMatchingFirstEmail` with `SUBJECT` `CONTAIN` and the 8 digit token.
5. Store `email.id` and the first attachment ID.
6. Call `/emails/{emailId}/attachments/{attachmentId}/metadata` and assert `name` and `contentType`.
7. Use `/base64` for attachment content when your ACCELQ flow needs JSON instead of binary bytes.

MailSlurp wait endpoints make this pattern stable in API test tools because the request waits for the mailbox state you need instead of relying on fixed sleeps.

## Troubleshooting

- A timeout from `waitForMatchingFirstEmail` usually means the subject token did not match, the reply was sent to a different address, or the message arrived without an attachment.
- If an older email is returned, use a fresh inbox per run and keep `unreadOnly=true`.
- If the receiver does not see the created inbox as the sender, confirm the send body includes `"senderId": "{{inboxId}}"`.
- If Postman cannot save a binary file during automation, use `/base64` and decode the `base64FileContents` value in the runner.
- If your expected file type is an extension such as `.pdf`, assert the metadata `name` for the extension and `contentType` for the MIME type, such as `application/pdf`.

## Complete request order

1. `POST /inboxes/withDefaults`
2. `POST /sendEmail` or your external service trigger
3. `POST /waitForMatchingFirstEmail`
4. `GET /emails/{emailId}/attachments`
5. `GET /emails/{emailId}/attachments/{attachmentId}/metadata`
6. `GET /emails/{emailId}/attachments/{attachmentId}` or `GET /emails/{emailId}/attachments/{attachmentId}/base64`

With these requests in a Postman collection, MailSlurp gives you a repeatable receive-email test that can be run manually, in collection runner, in Newman, or as ACCELQ API steps.
