I didn’t want my website code to handle all the email data going through the contact form. Instead, I wanted an automated workflow to handle all my sites emails. I thought it would be simple – until I spent two hours wondering why I was getting 403 errors.
Why do it in the first place?
I think automation platforms like n8n, Power Automate, Zapier are one of the best ways to understand modern systems. By seeing the connections, the authentications, the transfer of data, you learn about modern tech in a way that programming or networking just don’t provide.
It’s also great for those who don’t want to deep dive into coding; that’s not to say it’s easy, as you’ll soon see, but you don’t end up burying integrations under oceans of code.
Workflows also act like a hub for a particular function within your stack; it’s a visual dashboard, which in code, might be spread across a whole project.
When it comes to email, using workflow automation opens up countless outcomes which would be more intimidating with code:
- Send enquiries straight to your CRM
- Sync customer requests with calendars or task managers
- Add AI classification or summarisation
- Notify your team through Slack, Teams or Discord
- Swap email providers without changing your application code (this one is huge)
In short, it’s simpler, more accessible, and more scalable.
This article assumes you already have a contact form wired up with an API. This can be done through code or through no-code platforms.
Anyway, onto the automation.
How did I do it?
1. The contact form
This automation starts with the contact form. A user enters their query in the query box, and their email in the email box. These boxes will be relevant later.
In the image you can see ‘Hi’ is in the query box and an email is in the email box.
Clicking Send activates an API in the codebase.
The API specifies the headers and body of an HTTP request, which will be relevant later.
The API then sends the request on a specific path provided by the n8n webhook node. Speaking of which…
2. The webhook
In n8n, I picked a webhook node. This is the ideal tool because my application (website) is the one initiating the communication. The workflow just sits there waiting for it. Scheduled triggers would be wasteful, so it’s down to a webhook.
This is the webhook node. You can see at the top is the URL used to access the workflow. The HTTP method is set to POST because something is being changed.
Authentication is set to header auth because otherwise the webhook path is just an exposed online endpoint – I doubt anyone would exploit it but in the modern day, you want to make sure you’ve plugged as many of those gaps as possible.
Remember those HTTP headers I mentioned in the first step? The name of the credentials AND the webhook secret (the password) have to be set up exactly as they are in the API.
They also need to be saved as environment variables in your hosting service (I’m using Vercel). This is essential.
3. Create and send an email
Now what we need is for an email to come into my inbox, containing the information the user inputted to the contact form.
There’s a few ways to do this.
The most obvious is to set up credentials (yes more credentials) to allow n8n to actually log into a given email and send from there. I’m in favour of avoiding this wherever possible; it’s another entry, another opening that can be exploited.
So I used Resend, an email service made for developers in situations like these.
You don’t even need to set anything up in Resend for this, it’s really simple.
As you can see in the image, you set the operation to send, and set ‘from’ to onboarding@resend.dev, which is a default email just for this, so you don’t even need to set up credentials. All you have to do is install the Resend nodes in n8n.
Now, the query and email boxes I mentioned in the first step come back into play here.
All the data on the left side of the screen is part of the data that’s so far been passed through the workflow; you won’t see this until you actually execute a test workflow, and it’s essential you do this for pretty much every automation, so you can see the data you’re working with.
Among those data, are query, and email. You can drag and drop them into the text body. I have it set so the email will show the query text, and then ‘from’ followed by the email the user entered. Using the example entry I did in the first picture, my email would now show as it does in the image.
This is called dynamic mapping, and it’s one of my favourite things about automation. It makes things so simple.
Being able to see the data fields is so helpful for putting the data into the different formats needed for different platforms.
4. Return an email
This step isn’t essential but I think it’s nice for users to receive a polite response acknowledging their reaching out to you.
You’d think it would be similar to the last step, but it’s a bit more complex.
Because now the email appears to be coming from my domain. Appears is the important word; I use contact@benfosterdev.com, but that’s not a real email. The Resend service just pretends to send from that address.
It’s not actually as complex as it sounds; in Resend you go to domains, add the domain from which you wish your email to appear to return from (I use my domain benfosterdev.com). You then verify with your domain provider; if you use Cloudflare it’s very easy.
For this step you do need a credential with Resend, and you set that up using an API key from the Resend site.
In the image, you can see how I specify the name I want the email to come from, and how I’ve dynamically mapped the email field from the webhook node in the ‘To’ section; in my example, it will go to Judge@holden.net.
The subject will say BFdev, and the body will read as it does there in the image.
And that’s it!
Problems
Simple…
Or it should be…
As mentioned earlier, the HTTP request specifies both the headers and the body of the request.
And this is where n8n can trip you up – credentials are a beast of their own. What exactly are credentials in n8n?
They are sets of login details you create, either so your n8n can access a platform (like logging into an excel spreadsheet to make changes), or so that something else can access your workflow.
In this case, it’s the latter; an API is trying to access the workflow.
And when you write that API, the header has a name. And this must match the name value in the credential you build on n8n. That’s not the name of the credential; it’s the name VALUE of the credential.
I didn’t do this.
As a result, I spent hours spamming the API and staring angrily at error messages.
Don’t be like me, get your credential values right.
And that’s it. You now have a simple, functional contact form automation. There are some methods for tightening it up and making it more professional, but that’s for another article.
Salient points of this automation
- Dynamic mapping makes everything easier.
- You need to verify your domain to allow the Resend service to send on your behalf; this involves DNS SPF records and is a great opportunity to learn a bit more about how the internet works.
- Make sure to test the automation while building to pass the data required for mapping fields.
- And make sure your credentials are properly named!
About the author
I'm Ben Foster, a software developer building AI-powered automation systems for SMEs.
I write about Next.js, n8n, automation and software engineering at https://benfosterdev.com.





Top comments (0)