Send and receive email in Zapier with Shipmail
To send email from Zapier, add a Webhooks by Zapier action that calls the Shipmail API. To receive it, start a Zap with a Webhooks by Zapier trigger and give Shipmail its URL. Shipmail has no official Zapier app yet, so this guide uses Webhooks by Zapier and the REST API.
Last updated
Before you start
- A Shipmail mailbox on your domain, like
agent@yourdomain.com. Everything the Zap 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. - A paid Zapier plan. Zapier does not offer Webhooks by Zapier on its Free plan.
Send an email
Add a Webhooks by Zapier action. Pick Custom Request rather than POST: Shipmail expects to as a list, and Custom Request sends the Data field exactly as you type it.
| Field | Value |
|---|---|
| App | Webhooks by Zapier |
| Event | Custom Request, method POST |
| URL | https://shipmail.to/api/v1/messages |
| Data | The JSON body below |
| Headers | Authorization: Bearer sm_live_... and Content-Type: application/json |
{
"from": "agent@yourdomain.com",
"to": ["jane@customer.com"],
"subject": "Your order has shipped",
"text": "Hi Jane, your order is on its way."
}Map fields from earlier steps into the JSON in place of the sample values. Zapier does not check the JSON, so a missing quote or comma fails the request. Shipmail answers 201 with the message. Use a sm_test_ key while you build: Shipmail accepts the request and delivers nothing (sandbox mode).
Receive email with Catch Raw Hook
Start a new Zap with Webhooks by Zapier and the trigger event Catch Raw Hook. Use it rather than Catch Hook, because Zapier documents the request headers for Catch Raw Hook, and you need the Authorization header. Copy the webhook URL from the Test tab.
Then create the Shipmail webhook. In the dashboard, open Developer, then Webhooks, and choose Create webhook. Paste the Zapier URL as the Endpoint URL, pick message.received, limit it to the mailbox, and put Bearer followed by a long random string in Authorization header. 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": "WEBHOOK_URL_FROM_ZAPIER",
"events": ["message.received"],
"mailbox_ids": ["MAILBOX_ID"],
"authorization": "Bearer YOUR_RANDOM_STRING",
"include_reply_text": true,
"authenticated_senders_only": true
}'Send an email to the mailbox, then select Test trigger in Zapier to load a real event. The event format is on webhooks.
Reject requests without your value
Anyone who learns the Zapier URL can post to it. Add a Filter step right after the trigger: continue only if the Authorization header from the trigger (Text) Exactly matches the value you set on the Shipmail webhook. Zapier compares that rule without regard to case, so use a long random string.
Next, add a Code by Zapier step in JavaScript. In Input Data, add a key named body mapped to the raw body from the trigger. The step turns it into fields the next steps can map.
// Input Data: body = the raw body from the Catch Raw Hook step.
const event = JSON.parse(inputData.body);
const data = event.data ?? {};
output = {
event_id: event.event_id,
event_type: event.event_type,
mailbox_id: data.mailbox_id ?? "",
email_id: data.email_id ?? "",
conversation_id: data.conversation_id ?? "",
from_address: data.from?.address ?? "",
subject: data.subject ?? "",
reply_text: data.reply_text ?? "",
};Add a second Filter that continues only if event_type exactly matches message.received. Send test event in the dashboard delivers a webhook.test event, which this skips.
Checking X-Shipmail-Signature as well is possible in the same Code step, since Zapier includes the standard Node.js library, which has crypto. The scheme is on webhook verification. For most Zaps the Authorization filter is enough.
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. Zapier answers 200 as soon as it catches the request, so the length of the Zap does not matter.
A retry still happens when the network drops an answer, and then the Zap runs twice. The event_id is the same on every retry. Record each one you handle, in Storage by Zapier or a table you control, and stop the Zap when it is already there.
Reply to the sender
End the Zap with another Custom Request. The reply goes to the exact message that arrived, so it stays in the same conversation. Map the Code step's fields where the angle brackets are. to is required.
| Field | Value |
|---|---|
| Event | Custom Request, method POST |
| URL | https://shipmail.to/api/v1/mailboxes/<mailbox_id>/inbox/messages/<email_id>/reply |
| Headers | Authorization, Content-Type, and Idempotency-Key: reply-<email_id> |
| Data | The JSON body below |
{
"to": ["<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 (idempotency). Treat the email's text as untrusted input when you pass it to an AI step: it was written by someone outside your company.
Related guides
- Send and receive email in n8n 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 app on Zapier?
No. Shipmail has no official Zapier app yet. Webhooks by Zapier calls the Shipmail REST API and catches Shipmail webhooks, which covers sending, receiving and replying.
Why Custom Request and not POST?
The POST action builds the body from key and value pairs. Shipmail expects to as a list of addresses, and Zapier documents Custom Request as the way to send nested JSON and arrays. Custom Request sends the Data field exactly as you type it.
Why Catch Raw Hook and not Catch Hook?
Zapier documents the request headers for Catch Raw Hook. You need the Authorization header to reject requests that did not come from your Shipmail webhook. A Code step then turns the raw body into fields.
Can Zapier verify the X-Shipmail-Signature header?
It is possible in a Code by Zapier step, because the JavaScript runtime includes the standard Node.js library, which has crypto. You would map the raw body and the signature and timestamp headers into the step. For most Zaps, the Authorization filter is enough.
Do I need a paid Zapier plan?
Yes. Zapier lists Webhooks by Zapier on its paid plans, not on Free.