Sign in to fill these examples with your own keys. Sign in Start free trial

Send emails with n8n

Send from an n8n workflow with the HTTP Request node.

What you'll build

An n8n workflow that sends email through PostShiba with the HTTP Request node. You can also send with the Send Email node over SMTP, and start workflows from PostShiba delivery events with the Webhook node.

Before you start

  • An API key with Full access. See Create an API key. Support keys cannot send.
  • A verified sending domain. See Add and verify a domain. from must be an address on it.
  • A Transactional cluster that is ready to send. One-off notifications from a workflow belong on a transactional cluster, and the type is locked after create. See Clusters.

Install

Nothing to install. The HTTP Request, Send Email, Webhook, and Code nodes are built into n8n.

Send your first email

  1. Add an HTTP Request node to your workflow.
  2. On the node's Parameters tab, select Import cURL, paste this command, and select Import. n8n fills in the method, URL, headers, and body.
n8n-curl.sh
1curl -X POST https://app.postshiba.com/api/v1/emails \ 2 -H 'Authorization: Bearer YOUR_API_KEY' \ 3 -H 'Content-Type: application/json' \ 4 -d '{ 5 "from": "hello@mail.example.com", 6 "to": "you@example.com", 7 "subject": "Your receipt", 8 "text": "Thanks for your order." 9 }'
  1. Move the key into a credential so it is not stored in the node. Delete the Authorization header from Send Headers. Set Authentication to Generic Credential Type and Generic Auth Type to Header Auth, then create a credential with Name Authorization and Value Bearer YOUR_API_KEY.
  2. Map values from earlier nodes with expressions. For example, set to to {{ $json.email }} and subject to {{ $json.subject }}.
  3. Run the node. A queued send returns 201 with "queued": true. The message then shows under Events in the dashboard.

to takes one address or a comma-separated string. Every field is on Send emails with HTTP. To send on a specific cluster, add an X-Capsule-Cluster-Id header.

Send over SMTP instead

The Send Email node sends through an SMTP credential. Create an SMTP username and password first: open your cluster in the dashboard, go to its SMTP credentials, and choose Create SMTP credential. Copy the password right away, because it is shown once.

  1. Add a Send Email node and create a new SMTP credential with these values. The credential starts with port 465 and SSL/TLS on, so change both.
n8n-smtp.txt
1User: smtp_9 2Password: YOUR_PASSWORD 3Host: smtp.postshiba.com 4Port: 587 5SSL/TLS: off 6Disable STARTTLS: off 7Client Host Name: (leave empty)
  1. Save the credential. n8n tests the connection when you save.
  2. Set From Email to an address on your verified domain, such as hello@mail.example.com, and fill in To Email, Subject, and the body.

With SSL/TLS off, the connection starts plain on port 587 and upgrades with STARTTLS. Keep Disable STARTTLS off, because PostShiba accepts AUTH PLAIN only after STARTTLS. Leave the node's Ignore SSL Issues (Insecure) option off. Every SMTP setting is on Send emails with SMTP.

React to delivery events

PostShiba POSTs each delivery event to a URL as a JSON array in the SendGrid Event Webhook format. A Webhook node can receive it and start a workflow.

  1. Add a Webhook node. Set HTTP Method to POST, and under Add Option turn on Raw Body.
  2. Copy the Production URL. PostShiba needs a public https URL, and n8n registers the production URL when you publish the workflow.
  3. In PostShiba, open Webhooks, click Add endpoint, paste the URL, and save. Copy the Signing secret from the endpoint page. See Managing webhooks.
  4. Add a Code node after the Webhook node, in Run Once for All Items mode with JavaScript. It checks the signature and outputs one item per event.
n8n-verify.js
1const crypto = require('crypto') 2 3const secret = 'YOUR_SIGNING_SECRET' 4const { headers } = $input.first().json 5const raw = await this.helpers.getBinaryDataBuffer(0, 'data') 6 7const timestamp = headers['x-capsule-timestamp'] || '' 8const given = (headers['x-capsule-signature'] || '').replace(/^sha256=/, '') 9const expected = crypto.createHmac('sha256', secret) 10 .update(`${timestamp}.`) 11 .update(raw) 12 .digest('hex') 13 14const a = Buffer.from(expected) 15const b = Buffer.from(given) 16if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) { 17 throw new Error('Invalid PostShiba signature') 18} 19 20return JSON.parse(raw.toString('utf8')).map((event) => ({ json: event }))
  1. Click Send test event on the endpoint in PostShiba. The test event has "test": true.

The signature covers the exact bytes of the body, so the check reads the raw body that Raw Body stores as binary data, not the parsed JSON. With Respond set to Immediately, PostShiba gets 200 right away, and a bad signature stops the workflow at the Code node.

n8n Cloud allows crypto in the Code node. On self-hosted n8n, set NODE_FUNCTION_ALLOW_BUILTIN=crypto. If your instance uses task runners, set it on the task runners. Fields on each event are on Event types. Use sg_event_id to drop duplicates when a delivery is retried.

Troubleshooting

What you see What to do
401 Invalid token or no user signed in The API key is missing or mistyped. Check that the credential Value starts with Bearer , and that the imported Authorization header is removed.
403 forbidden Support keys cannot send. Use a Full access key.
403 domain_unverified or domain_suspended Use a from address on a verified domain. Resume a paused domain from Managing domains.
403 kyc_required or 550 kyc_required Your team is pending production approval. Until then, send only to team members, live inbox addresses, and inbox forward-to addresses. See Does PostShiba require production approval?
429 throttled or 451 4.7.0 hourly send limit reached The cluster is at its hourly throttle or 24-hour cap, and the message was not kept. Retry later. See What happens at your cap.
429 rate_limited More than 300 send requests in one minute on one API key. Use the HTTP Request node's Batching option to slow down.
The SMTP credential test fails with an SSL or timeout error Set Port to 587 and turn SSL/TLS off. Port 465 is not offered.
550 unverified domain or 550 from header not aligned with verified domain Set From Email to an address on your verified domain.
403 suppressed, 403 firewall, 550 suppressed, or 550 firewall: <rule> The recipient is on the suppression list or failed an email firewall check.
The Code node throws Invalid PostShiba signature Check the signing secret, and that Raw Body is on in the Webhook node.
The Code node can't load crypto On self-hosted n8n, set NODE_FUNCTION_ALLOW_BUILTIN=crypto and restart.

Next steps