Logo
Back
background

BFblog

Automating Contact Form Emails with n8n


Ben Foster

29th July 2026

10 min read


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 site's 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?

Automation platforms like n8n, Power Automate, and Zapier are one of the best ways to understand modern systems. By seeing the connections, authentications, and transfer of data, you learn about modern tech in a way that programming or networking just don't provide.

They're also great for people who don't want to deep dive into coding. That's not to say they are easy, 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, workflow automation opens up a lot of useful outcomes:

  • 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

In short, it is simpler, more accessible, and more scalable.

This article assumes you already have a contact form wired up with an API. That can be done through code or through no-code platforms.

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 fields will be relevant later.

The first image shows "Hi" in the query box and an email in the email box.

Image 1 showing the contact form with the query and email fields filled in

Clicking Send activates an API in the codebase. The API specifies the headers and body of an HTTP request, which becomes important later. The API then sends the request on the path provided by the n8n webhook node.

2. The webhook

In n8n, I picked a webhook node. This is the ideal tool because my application is the one initiating the communication. The workflow just sits there waiting for it. Scheduled triggers would be wasteful, so it is a webhook.

Image 2 showing the n8n webhook node

You can see the URL used to access the workflow at the top. 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. The webhook secret and credential name need to match exactly what is set in the API.

They also need to be saved as environment variables in your hosting service. I use Vercel, and this part is essential.

3. Create and send an email

Now I need an email to come into my inbox containing the information the user entered in the contact form. There are a few ways to do this.

The obvious option is to set up credentials so n8n can log into an email account and send from there. I try to avoid that wherever possible because it creates another opening that can be exploited.

So I used Resend, an email service made for developers in situations like these.

Image 3 showing the Resend email send node

You can set the operation to send and use onboarding@resend.dev as the from address. That is a default email for this flow, so you do not need to set up credentials just to test it. You only need to install the Resend nodes in n8n.

The query and email boxes from the first step come back into play here. The data on the left side of the screen is the data passed through the workflow so far, and you can drag those fields into the body.

Image 4 showing the email body with dynamic data mapping

I set it so the email shows the query text, followed by from and then the email address the user entered. This is called dynamic mapping, and it is one of my favourite things about automation.

4. Return an email

This step is not essential, but I think it is nice for users to receive a polite response acknowledging their message.

It is a little more complex because now the email appears to be coming from my domain. I use contact@benfosterdev.com, but that is not a real mailbox. Resend just pretends to send from that address.

In Resend, you add the domain you want to send from and verify it with your domain provider. If you use Cloudflare, that part is fairly straightforward.

For this step you need a credential with Resend, which you set up using an API key from the Resend site.

Image 5 showing the return email configuration

The image shows the name I want the email to come from and the email field dynamically mapped from the webhook node in the To section. In my example, it will go to Judge@holden.net.

The subject says BFdev, and the body reads as it does in the image.

Problems

Simple.

Or it should be.

As mentioned earlier, the HTTP request specifies both the headers and the body of the request. This is where n8n can trip you up because credentials are a beast of their own.

What exactly are credentials in n8n?

They are sets of login details you create, either so n8n can access a platform or so something else can access your workflow.

In this case, it is the latter. An API is trying to access the workflow. And when you write that API, the header has a name. That name must match the name value in the credential you build in n8n.

I did not 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.

That is it. You now have a simple, functional contact form automation. There are ways to tighten it up and make it more professional, but that is for another article.

Salient points of this automation

  • Dynamic mapping makes everything easier
  • You need to verify your domain to allow Resend to send on your behalf. That involves DNS SPF records and is a great opportunity to learn more about how the internet works
  • Make sure to test the automation while building it so the data needed for mapping fields is present
  • Make sure your credentials are properly named