How to create simple email form in your NodeJS website.

July 10, 2022

3 min read

Most webpages have some contact form, usually not very fancy and the backend behind it can be SalesForce, any other variation of lead generation software but usually it just sends email.

Sending emails is not trivial, you need to have an SMTP server and that alone will add to your costs. Fortunately, we live in an age where everything is a service and API. There are tons of services that can send emails to you. My goal was to do it as cheaply as possible (preferably for free). I was expecting at most about 5 emails per day.

After some research, I decided to use Send In Blue. Their free plan has 300 emails per day (more than enough for me), you do not need a credit card to sign up, no DNS shenanigans and their API is very straightforward.

API endpoint in NextJS

NextJS offers a friendly and easy way to create API endpoints from where you can call any external APIs without actually exposing your secret keys to the browser.

I got the API key from Send in Blue with the help of this awesome help page, and add the key into my .env.local file.

NEXT_PUBLIC_SEND_IN_BLUE_KEY=xxxxapikeyxxxx

I also put the key into the Vercel Environment variables manager with the same name.

I created a new file api/email.js from where I will send the email via Send In Blue API.

const sendInBlueKey = process.env.NEXT_PUBLIC_SEND_IN_BLUE_KEY

export default async function handler(req, res) {

    const body = req.body

    const resp = await fetch('https://api.sendinblue.com/v3/smtp/email', {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
          'api-key': sendInBlueKey
        },
        body: JSON.stringify({
            "sender":{  
                "name": body.name,
                "email": body.email
             },
             "to":[  
                {  
                   "email": "myemail@ppolivka.com",
                   "name": "Pavel Polivka"
                }
             ],
             "subject":`Contact Form Eamil From ${body.name}`,
             "htmlContent":`
                <html>
                    <head></head>
                    <body>
                        From: ${body.name} <br/>
                        Message: ${body.message} <br/>
                    </body>
                </html>
            `
        })
    });

    res.status(200).end()
}

From the form, I am getting the name and email of the sender and a message. I am sending that (the sender is the email from the form) to my email address so that I can reply to my email client.

Contact Form

Then I created a contact form component. It's a simple form with three fields and the submit button. All the sending magic is happening in the handleSubmit function.

import TextField from '@mui/material/TextField';
import Button from '@mui/material/Button';
import {useState} from 'react';

export default function Contact() {

    const [send, setSend] = useState(false);

    async function handleSubmit(event) {
        event.preventDefault()
        const data = {
            email: event.target.email.value,
            name: event.target.name.value,
            message: event.target.message.value,
        }

        const JSONdata = JSON.stringify(data)

        const endpoint = '/api/email'
        
        const options = {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSONdata,
        }

        const response = await fetch(endpoint, options)

        setSend(true)
    }

    let content;

    if (send) {
        content = <>
            <p>Thank you for contacting me!</p>
        </>
    } else {
        content = <>
            <form onSubmit={handleSubmit}>
                <TextField id="email" label="Email" variant="outlined" required />
                <TextField id="name" label="Name" variant="outlined" required />
                <TextField id="message" label="Message" variant="outlined" required multiline rows={4} />

                <Button variant="contained" type="submit">Send</Button>
            </form>
        </>
    }

	return (
		<>
            {content}
        </>
        );
}


I am using React Material UI, but you can use any UI or just normal inputs.

This is all you need. Simple and elegant. It was done in an hour.

Good luck coding.

← Back to blog