Connecting SendGrid to n8n: transactional sending, marketing contacts, and Event Webhook signature verification
Published 29 August 2026 · 6 min read
A transactional email that sends without error doesn't mean it arrives. SendGrid (acquired by Twilio in 2019) remains one of the most widely used sending APIs, with one feature neither Postmark nor Resend can match: n8n gives it a full native node, capable of sending an email and managing marketing contacts without a raw HTTP call. The trade-off shows up on the events side: there's no dedicated trigger, and the webhook that reports bounces and clicks is signed with an asymmetric algorithm (ECDSA) that most n8n tutorials, calibrated around Stripe-style HMAC signatures, simply don't cover.
What the native SendGrid node covers — and what it doesn't
n8n's SendGrid node exposes two main resources: Mail, for sending an email, and Contact, for creating, fetching, updating, or deleting a contact and attaching it to a marketing list (the underlying API is /v3/marketing/contacts). Unlike Postmark or Resend, whose email sending must go through a raw HTTP Request node, SendGrid requires no manual API call setup for either of these two uses.
What's missing, on the other hand, is a trigger: there's no "SendGrid Trigger" that automatically receives deliverability events. For bounces, opens, and clicks, you have to build reception yourself with a Webhook node — exactly as with Resend — only the sending side differs between the two services.
Sending a transactional email with the SendGrid node
On the Mail resource, Send operation, the node expects a verified From address, one or more recipients, a subject, and content (text and/or HTML). As with most transactional sending APIs, the sender address must be tied to a validated Sender Authentication — either a single confirmed address via email verification, or a domain verified through DNS records (SPF and DKIM) in SendGrid's Sender Authentication Settings. Skip this step and every send fails before it ever reaches a recipient.
To attach a file (quote, invoice), the Attachments field accepts base64-encoded content with its MIME type — content produced upstream by a PDF invoice generated in the same workflow or pulled via the Convert to File node. For emails built from a SendGrid Dynamic Template (layout managed on SendGrid's side rather than inside the workflow), a direct API call via HTTP Request with the template_id field remains the more reliable option: the native node fits best when the content itself is generated dynamically inside n8n.
Managing marketing contacts and lists
The Contact resource lets you create or update a contact with its custom fields and attach it to one or more lists. One detail worth knowing before chaining operations: creating contacts on /v3/marketing/contacts is asynchronous on SendGrid's side — the call returns a job identifier rather than an immediate confirmation. A workflow that chains "create the contact" straight into "add it to a campaign" within the same execution can end up acting on a contact that isn't fully indexed yet; a short delay, or a check via the Get operation before the next step, avoids this kind of intermittent false negative.
Contact list quality directly affects sending reputation. A study that's become a reference in systems security, Kanich, Kreibich, Levchenko, et al. (2008), Spamalytics: An Empirical Analysis of Spam Marketing Conversion, published at ACM CCS, measured from inside a botnet the actual conversion rate of an unsolicited email campaign: on the order of a handful of conversions per several million messages sent. That figure illustrates, by contrast, why mailbox providers treat any volume of sending to disengaged addresses as a risk signal — and why a clean contact list (honored unsubscribes, hard-bounced addresses removed) protects the deliverability of every send, transactional included, far more effectively than any single technical setting.
Receiving events with a Webhook node
In SendGrid's Mail Settings, the Event Webhook tab expects a URL — n8n's Webhook node, in production mode — and a selection of events to forward, split into two families: deliverability events (processed, delivered, bounce, dropped, deferred) and engagement events (open, click, unsubscribe, spam_report). SendGrid batches several events into a single POST call, as a JSON array — the workflow needs to iterate over the received list rather than treat it as one object, with a Split Out node if each event needs separate downstream handling.
An IF or Switch node then separates the cases worth acting on: a bounce-type event (invalid address, permanent) doesn't call for the same handling as a blocked-type one (temporary rejection, worth retrying) — a distinction close to the hard-versus-soft-bounce split already seen with Postmark.
Verifying the Event Webhook's ECDSA signature
Once Signed Event Webhook Requests is enabled in Mail Settings, every incoming call carries two headers: X-Twilio-Email-Event-Webhook-Signature (a base64-encoded signature) and X-Twilio-Email-Event-Webhook-Timestamp. Verification relies on ECDSA, a public/private key scheme formalized by Johnson, Menezes, and Vanstone (2001), The Elliptic Curve Digital Signature Algorithm (ECDSA), published in the International Journal of Information Security — and that's a structural difference from the HMAC verification described in our n8n webhook security guide: here, there's no shared secret, only the public key (retrievable from those same Mail Settings) lets you verify a signature produced with the private key SendGrid never shares.
The signed message is the exact concatenation of the timestamp and the raw request body — which is why enabling the Webhook node's Raw Body option matters: without it, n8n re-parses the JSON before the signature gets computed, which breaks verification every time. A Code node placed right after the Webhook does the check:
const crypto = require('crypto');
const publicKeyPem =
'-----BEGIN PUBLIC KEY-----\n' +
$env.SENDGRID_WEBHOOK_PUBLIC_KEY +
'\n-----END PUBLIC KEY-----';
const signature = $request.headers['x-twilio-email-event-webhook-signature'];
const timestamp = $request.headers['x-twilio-email-event-webhook-timestamp'];
const rawBody = $request.body; // raw, thanks to the Webhook node's Raw Body option
const verifier = crypto.createVerify('SHA256');
verifier.update(timestamp + rawBody);
verifier.end();
if (!verifier.verify(publicKeyPem, signature, 'base64')) {
throw new Error('Invalid SendGrid signature');
}
return JSON.parse(rawBody).map((event) => ({ json: event }));
As with any signature check, wiring this Code node to an explicit error output instead of letting the exception bubble up as-is lets you return a clean rejection to SendGrid without the incident looking like an internal failure.
A concrete case: invoice sent, tracked, and the contact cleaned up on first bounce
- An invoicing workflow generates the PDF and triggers the send via the SendGrid node (Mail resource), keeping the message ID alongside the invoice number in a Supabase table.
- The Webhook node, signature verified, receives
deliveredandbounceevents and updates that same table. - On a permanent
bounce, the matching contact gets marked invalid via the SendGrid node's Update operation — it won't receive any further sends until the address is fixed manually, and a Slack alert tells the finance team a follow-up through another channel is needed.
Common pitfalls
- Verifying the signature against a body already re-parsed as JSON instead of the raw body: the signature will never match, no matter how correct the rest of the code is.
- Treating the Event Webhook payload as a single object, when SendGrid always batches several events into the same JSON array sent in one request.
- Confusing HMAC and ECDSA: copying verification code written for a Stripe or GitHub webhook won't work here — the two signature schemes aren't interchangeable.
- Skipping Sender Authentication before the first send: without a verified domain or confirmed address, every call to the Mail resource fails, regardless of how correctly the node itself is configured.
Going further
What SendGrid adds over Postmark and Resend is native marketing contact management right inside n8n — handy for running transactional sending and a mailing list in the same workflow without juggling a separate tool like Brevo. That same need for traceability — who received what, with what status, and what fix got applied on failure — is exactly what the Compliance & Audit Pack (€149) is built for, with a Supabase logging block already wired to plug into a signed webhook's output. Paired with the Inbox AI Pack (€79) for sorting incoming replies, the Full FlowKit Bundle (€269 instead of €347 bought separately) covers the full lifecycle of an email, from sending to fixing the contact when it fails.
FAQ
Frequently asked questions
Does n8n's SendGrid node let you receive events (bounce, click, open)?
No. The SendGrid node covers sending email and managing marketing contacts and lists, but there is no native trigger for events. Receiving them requires a plain Webhook node, whose production URL you paste into the Event Webhook tab of SendGrid's Mail Settings, along with a manual selection of which events to send (bounce, dropped, deferred, open, click, unsubscribe…).
Why does SendGrid signature verification consistently fail inside n8n?
The most common cause: the Webhook node re-parsed the request body into JSON before the Code node computed the expected signature, while SendGrid signs the exact raw bytes of the payload. Any serialization difference (key order, whitespace) invalidates the signature. The fix is to enable the Webhook node's Raw Body option so you work against the exact raw string SendGrid sent.
Should SendGrid's signature be verified with HMAC, like Stripe or GitHub?
No, and that's an important distinction to know before writing the Code node. Stripe and GitHub sign with HMAC (a shared secret, the same key on both sides); SendGrid signs with ECDSA (a private key held by SendGrid, a public key you fetch from the dashboard to verify on n8n's side). The verification code isn't interchangeable between services: crypto.createHmac won't work here — you need crypto.createVerify.
What's the difference between SendGrid and Postmark or Resend for n8n?
SendGrid is the only one of the three with a full native action node in n8n: sending email and managing marketing contacts without going through HTTP Request. On the other hand, none of the three offers a native trigger equivalent to the Postmark Trigger for events — SendGrid, like Resend, requires building event reception yourself via a Webhook node, with SendGrid additionally requiring a more complex asymmetric signature check than a plain HMAC.
Bundle FlowKit Complet
€269