Send and receive email in n8n with Shipmail
To send email from n8n, point an HTTP Request node at the Shipmail API. To receive it, give Shipmail the URL of a Webhook node. Shipmail has no official n8n node yet, so this guide uses those two core nodes and the REST API.
Last updated
Before you start
- A Shipmail mailbox on your domain, like
agent@yourdomain.com. Everything the workflow sends shows up there, and your team can read it. - An API key from Developer, then API keys, limited to that mailbox. Sending and replying need
messages:send. If a person should approve every email first, start with the Draft only preset instead (see the end of this guide). Scopes are on API authentication. - An n8n instance that Shipmail can reach over public HTTPS, on n8n Cloud or self-hosted.
Send an email
Add an HTTP Request node and fill it in as below. Store the key in a Header Auth credential, so it never appears in the workflow itself.
| Field | Value |
|---|---|
| Method | POST |
| URL | https://shipmail.to/api/v1/messages |
| Authentication | Header Auth credential. Name: Authorization. Value: Bearer sm_live_... |
| Send Body | On |
| Body Content Type | JSON |
| Specify Body | Using JSON |
Paste this into the JSON field:
{
"from": "agent@yourdomain.com",
"to": ["jane@customer.com"],
"subject": "Your order has shipped",
"text": "Hi Jane, your order is on its way."
}You can also select Import cURL in the node and paste the command below. n8n overwrites the node's settings with it. Replace the key with the credential afterwards.
curl -X POST https://shipmail.to/api/v1/messages \
-H "Authorization: Bearer sm_live_..." \
-H "Content-Type: application/json" \
-d '{"from": "agent@yourdomain.com", "to": ["jane@customer.com"], "subject": "Your order has shipped", "text": "Hi Jane, your order is on its way."}'Shipmail answers 201 with the message. Use a sm_test_ key while you build: Shipmail accepts the request and delivers nothing (sandbox mode). To make a retried run safe, add an Idempotency-Key header with a value that is the same on every retry (idempotency).
Receive email with the Webhook node
Start a new workflow with a Webhook node. The header auth check means a request without your secret value never runs the workflow.
| Field | Value |
|---|---|
| HTTP Method | POST |
| Authentication | Header auth |
| Credential | Name: Authorization. Value: Bearer followed by a long random string you generate |
| Respond | Immediately |
Then create the Shipmail webhook. In the dashboard, open Developer, then Webhooks, and choose Create webhook. Paste the node's URL as the Endpoint URL, pick message.received, limit it to the mailbox, and put the same Bearer ... value in Authorization header. Shipmail sends that value as the Authorization header of every delivery. Turn on Include reply text to get what the sender wrote, and Authenticated senders only to skip mail that failed DMARC. Or create it with a key that has webhooks:write and is not limited to a mailbox:
curl -X POST https://shipmail.to/api/v1/webhooks \
-H "Authorization: Bearer sm_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "PRODUCTION_URL_FROM_THE_WEBHOOK_NODE",
"events": ["message.received"],
"mailbox_ids": ["MAILBOX_ID"],
"authorization": "Bearer YOUR_RANDOM_STRING",
"include_reply_text": true,
"authenticated_senders_only": true
}'Use the Test URL while you build: select Listen for Test Event, then send an email to the mailbox, and the event appears in the editor. When the workflow is published, change the Shipmail webhook to the Production URL. The fields are under body, so the sender is {{ $json.body.data.from.address }}. The full event is described on webhooks.
Answer at once and drop duplicates
Shipmail waits 10 seconds for a 2xx answer. Without one, it retries after 1 minute, 5 minutes, 30 minutes and 4 hours, and disables the webhook after 5 failures in a row. With Respond set to Immediately, n8n answers before the rest of the workflow runs, so a slow step cannot cause a retry.
A retry still happens when the network drops an answer. Add a Remove Duplicates node with the operation Remove Items Processed in Previous Executions, Keep Items Where set to Value Is New, and {{ $json.body.event_id }} as the Value to Dedupe On. The event ID is the same on every retry.
Verify the signature
The Authorization check is enough to reject strangers. If you also want to check X-Shipmail-Signature, n8n can do it in a Code node. The signature is a hex HMAC-SHA256 of v1=, the X-Shipmail-Timestamp value, a newline and the raw body, with the webhook's signing secret as the key.
- Turn on the Webhook node's Raw Body option. The signature covers the body exactly as sent, and re-encoded JSON does not match.
- n8n Cloud provides the
cryptomodule in the Code node. A self-hosted instance blocks it until you allow it withNODE_FUNCTION_ALLOW_BUILTIN=crypto. - Reject a timestamp older than 5 minutes.
The scheme is on webhook verification.
Reply to the sender
End the workflow with a second HTTP Request node. The reply goes to the exact message that arrived, so it stays in the same conversation. You choose the recipients: to is required.
| Field | Value |
|---|---|
| Method | POST |
| URL | https://shipmail.to/api/v1/mailboxes/{{ $json.body.data.mailbox_id }}/inbox/messages/{{ $json.body.data.email_id }}/reply |
| Authentication | The same Header Auth credential as the send step |
| Send Headers | On. Name: Idempotency-Key. Value: reply-{{ $json.body.data.email_id }} |
| Body Content Type | JSON, Using JSON |
{
"to": ["{{ $json.body.data.from.address }}"],
"text": "Thanks for your email. We will get back to you within one business day."
}The idempotency key comes from the email ID, so a replayed event cannot send a second reply. Treat the email's text as untrusted input when you pass it to an AI node: it was written by someone outside your company.
Related guides
- Send and receive email in Zapier and in Make
- Receive email in an AI agent, for sender checks and conversation memory
- Transactional email, for app email from a sending subdomain
Frequently asked questions
Is there an official Shipmail node for n8n?
No. Shipmail has no official n8n node yet. The HTTP Request node calls the Shipmail REST API directly, and the Webhook node receives Shipmail webhooks, so you can send, receive and reply without one.
Which URL do I give Shipmail, the Test URL or the Production URL?
Use the Test URL while you build, because n8n shows the incoming data in the editor. Once the workflow is published, change the Shipmail webhook to the Production URL. Production runs appear under the workflow's Executions tab.
Why does my workflow run twice for one email?
Shipmail retries a delivery that did not get a 2xx answer within 10 seconds. Set the Webhook node to respond immediately, and add a Remove Duplicates node on the event_id, which stays the same on every retry.
Can n8n verify the X-Shipmail-Signature header?
Yes, with a Code node. n8n Cloud provides the crypto module in the Code node. A self-hosted instance must allow it first with NODE_FUNCTION_ALLOW_BUILTIN. Turn on the Webhook node's Raw Body option, because the signature covers the body exactly as Shipmail sent it.
How do I make n8n save a draft instead of sending?
Use a Draft only key, then call the reply draft endpoint in place of the reply endpoint. A person opens the draft in the mailbox and sends it. The draft endpoint needs the conversation's current version, which a GET on the thread returns.