Sending Emails in NextJs via Nodemailer
Tags: nodemailer, nextjs, webdev, react
Published: 2024-07-12 18:40:58

Sending emails is a common requirement in many web applications, whether it's for user registration, password resets, notifications, newsletters or other purposes. In this blog detailed post, I'll tell you how to send emails in a Next.js application using Nodemailer, a popular Node.js library for sending emails.

## Why use nodemailer?

Nodemailer is a robust and easy-to-use library that supports various email transport methods, including SMTP, Gmail, and more. It's highly configurable and can be used to send HTML emails, attachments, and even template-based emails. And the most important thing, it is free!!

## Setting Up Your Next.js Project

After setting up your nextjs projects install the nodemailer library:
```npm install nodemailer```
If you are using typescript like me, then you will also need to install it within its types:
```npm i --save-dev @types/nodemailer```

## Configure Nodemailer

Next, configure nodemailer and export a function called `sendMail` or whatever is best fit for you. Here is complete code of Nodemailer configuration.

`lib/send-mail.ts`

```typescript
'use server';
import nodemailer from 'nodemailer';
const SMTP_SERVER_HOST = process.env.SMTP_SERVER_HOST;
const SMTP_SERVER_USERNAME = process.env.SMTP_SERVER_USERNAME;
const SMTP_SERVER_PASSWORD = process.env.SMTP_SERVER_PASSWORD;
const SITE_MAIL_RECIEVER = process.env.SITE_MAIL_RECIEVER;
const transporter = nodemailer.createTransport({
  service: 'gmail',
  host: SMTP_SERVER_HOST,
  port: 587,
  secure: true,
  auth: {
    user: SMTP_SERVER_USERNAME,
    pass: SMTP_SERVER_PASSWORD,
  },
});

export async function sendMail({
  email,
  sendTo,
  subject,
  text,
  html,
}: {
  email: string;
  sendTo?: string;
  subject: string;
  text: string;
  html?: string;
}) {
  try {
    const isVerified = await transporter.verify();
  } catch (error) {
    console.error('Something Went Wrong', SMTP_SERVER_USERNAME, SMTP_SERVER_PASSWORD, error);
    return;
  }
  const info = await transporter.sendMail({
    from: email,
    to: sendTo || SITE_MAIL_RECIEVER,
    subject: subject,
    text: text,
    html: html ? html : '',
  });
  console.log('Message Sent', info.messageId);
  console.log('Mail sent to', SITE_MAIL_RECIEVER);
  return info;
}
``` 

In the above file, we set up Nodemailer with Gmail's SMTP service and create a sendEmail function that sends an email using the provided options.
NOTE: You will need to generate an app password for implementing `nodemailer`. You can generate this app password in `manage account settings` of your google account, but you will need to enable two-step-verification first!
Use that app password as your nodemailer `SMTP_SERVER_PASSWORD`, for username, write the You Gmail address.

All set, now add `.env.local` because we cannot expose our passwords or other sensitive information:

```.env
SMTP_SERVER_USERNAME=your-email-address
SMTP_SERVER_PASSWORD=your-app-password
SMTP_SERVER_HOST=email-smtp.us-east-1.amazonaws.com
SITE_MAIL_RECIEVER=mail-receiver email
```


## Send FormData via nodemailer

Now lets run our function to send formData to my email:

```tsx
'use client';
import { useForm } from 'react-hook-form';
import { Form, FormField, FormControl, FormItem, FormMessage } from '../ui/form';
import { Input } from '../ui/input';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { Textarea } from '../ui/textarea';
import { sendMail } from '@/lib/send-mail';
import { toast } from 'sonner';
import { Button } from '../ui/button';
const contactFormSchema = z.object({
  name: z.string().min(2, { message: 'Please Enter Your Name' }),
  email: z.string().email({ message: 'Please Enter a Valid Email Address' }),
  message: z
    .string()
    .min(10, { message: 'Please make sure your message is at least 10 characters long.' }),
});
export default function ContactForm() {
  const form = useForm<z.infer<typeof contactFormSchema>>({
    resolver: zodResolver(contactFormSchema),
    defaultValues: {
      name: '',
      email: '',
      message: '',
    },
  });
  const isLoading = form.formState.isSubmitting;
  const onSubmit = async (values: z.infer<typeof contactFormSchema>) => {
    const mailText = `Name: ${values.name}\n  Email: ${values.email}\nMessage: ${values.message}`;
    const response = await sendMail({
      email: values.email,
      subject: 'New Contact Us Form',
      text: mailText,
    });
    if (response?.messageId) {
      toast.success('Application Submitted Successfully.');
    } else {
      toast.error('Failed To send application.');
    }
  };
  return (
    <Form {...form}>
      <form
        className="grid grid-cols-3 items-center p-4 lg:p-6"
        onSubmit={form.handleSubmit(onSubmit)}
      >
        <div className="col-span-3 flex flex-col gap-4 lg:col-span-3 lg:gap-6">
          <h2 className="lg:text-xl">Enter Your Good Name Here:</h2>
          <FormField
            control={form.control}
            name="name"
            render={({ field }) => (
              <FormItem>
                <FormControl>
                  <Input placeholder="John Doe" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <h2 className="lg:text-xl">Enter Your Email Address:</h2>
          <FormField
            control={form.control}
            name="email"
            render={({ field }) => (
              <FormItem>
                <FormControl>
                  <Input placeholder="john@example.com" {...field} />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <h2 className="lg:text-xl">Enter Your Message Here:</h2>
          <FormField
            control={form.control}
            name="message"
            render={({ field }) => (
              <FormItem>
                <FormControl>
                  <Textarea
                    {...field}
                    placeholder="My question is which framework do you prefer to use?"
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />
          <Button disabled={isLoading}>{isLoading ? 'Sending.....' : 'Send'}</Button>
        </div>
      </form>
    </Form>
  );
}
```
The above is a simple contact form, when form submission is successful it will show a success toast otherwise an error toast.


## Conclusion

Sending emails in a Next.js application is straightforward with Nodemailer. By following the steps outlined in this blog post, you can easily integrate email functionality into your Next.js projects, whether for contact forms, notifications, newsletters or other purposes. Give it a try and see how it can enhance your application's communication capabilities!

Feel free to ask questions if you have any. Please leave you feedback as well.