Sending
Send mail from an inbox, to test how your app handles incoming email.
Inboxes can send as well as receive. Use it when the app under test reads mail: replies to a support ticket, mail-to-import, or inbound parsing. To send your app's own receipts and notifications, see Transactional mail.
const inbox = await mailwurf.createInbox();
const sent = await inbox.send({
to: "support@staging.acme.com",
subject: "Order 1042 arrived damaged",
text: "The box was crushed.",
});
sent.status; // "queued"The message is sent from inbox.sender_address, which is inbox.address except on a domain with its own mail server: there billing@send.acme.com sends as billing@acme.com. The sender cannot be changed per message.
An inbox on a custom domain can only send once sending is on for that domain. Otherwise the call returns 400 Sending is off for {domain}. Turn it on in the domain settings.
Fields
| Field | Required | Meaning |
|---|---|---|
to | yes | One address, or Name <address>. |
subject | yes | Must not be empty. |
text | text or html | Plain-text body. |
html | text or html | HTML body. |
inReplyTo | no | Id of a received message. The mail is sent as a reply to it. |
attachments | no | Up to 10 files. See Attachments. |
Over HTTP the same call is POST /v1/inboxes/{id}/messages, with the reply field named in_reply_to. It returns 202:
{ "id": "outbox_Xk3f9x2Ab7QzLp0W", "status": "queued" }Between two inboxes
Mail to another Mailwurf inbox is delivered directly, so the recipient can wait for it:
const alice = await mailwurf.createInbox();
const bob = await mailwurf.createInbox();
await alice.send({ to: bob.address, subject: "Hello", text: "ping" });
const mail = await bob.waitFor({ subject: "Hello" });
mail.from; // alice.addressThe recipient must be an active inbox. An unknown or expired address on the Mailwurf mail domain returns 404 recipient mailbox not found.
Replies
Reply to a received message, so the app under test sees a threaded answer:
const question = await inbox.waitFor({ subject: "How can we help?" });
await inbox.send({
to: "support@staging.acme.com",
subject: `Re: ${question.subject}`,
text: "The tracking link does not work.",
inReplyTo: question.id,
});Attachments
Each file has a filename, its content as bytes (Uint8Array, Buffer) or as a base64 string, and an optional contentType. Without contentType, the type is guessed from the file name.
import { readFile } from "node:fs/promises";
await inbox.send({
to: "import@staging.acme.com",
subject: "Orders for October",
text: "See attached.",
attachments: [{ filename: "orders.csv", content: await readFile("fixtures/orders.csv") }],
});Over HTTP, attachments is an array of { "filename", "content", "content_type" } with content base64-encoded. Invalid entries return 400.
Delivery
Sending is asynchronous. The call returns when the message is queued, not when it is delivered.
- Mail to the internet is delivered to the recipient's mail server and retried for a while when that server is temporarily unavailable.
- If the receiving server rejects the message, it is marked failed and not retried.
- The dashboard shows each sent message and its status under the inbox's Mail view. See Read the mail.
For better deliverability to external servers, send from an address on a verified custom domain.
Limits
- 60 sends per organization per minute. More return
429 too many sends. - 5 MiB per message, attachments included. Larger messages return
400. - 10 attachments per message.
- One recipient per send.
Mailwurf