π Automate Emails with Mailgun and Next.js
Yeah... you can automate that sh!t.
Ever sent emails via code only to watch them morph into a Pollock painting when you open them in Microsoft Outlook? Yeah, me too, and guess what? Outlook still holds something like 75% of the corporate email market. So unless your audience is the Amish, you're gonna have to deal with it.
Why Mailgun? π¬
Deliverability: You probably want your emails to arrive to the person you send it to.
Templates: Pre-built templates which make the styling consistent across various email apps.
Analytics: Know exactly how many people ignored your email.
Scalability: Send a shiiiettload of emails β Mailgun doesn't care, they like your money.
Free: Well almost, if you follow the trick below, you'll be able to send thousands of emails per month for less than the cost of your soy f**king latte with a twist of lemon.
Speed: Carrier pigeons aren't gonna cut it... though they must be fun.
Alright nerd, let's do it π¨βπ»
We'll walk through integrating Mailgun with Next.js. If you're using something else, well, GLHF. The principles are the same, but your journey will be more rough, like my pipeline, or using Bitbucket instead of GitHub.
Step 1: npm i
, baby
First things first, you'll need the Mailgun SDK.
1npm install mailgun.js
Step 2: Set Up Your Mailgun Account
Head over to Mailgun and sign up. They have a pay-as-you-go plan that's hidden because...as i said...they like your money. Sign up for the free trial, then cancel to downgrade to the plan where you pay $1 for 1,000 emails. Bargain.
Step 3: Secure Your API Keys
Create a .env.local
file in your project's root directory.
1MAILGUN_API_KEY=your-mailgun-api-key
2MAILGUN_DOMAIN=your-mailgun-domain
3MAILGUN_FROM_DEFAULT=Your Name <you@mail.yourdomain.com>
Your "from default" might not need to be environment specific, put it where you want, I'm not your mother.
Notice we aren't prefixing these with NEXT_PUBLIC. Thats because... say it with me... they are secret.
Step 4: Set Up the Mailgun Client
Create a utility file to initialise Mailgun.
1// lib/mailgun.js
2
3import formData from 'form-data';
4import Mailgun from 'mailgun.js';
5
6const mailgun = new Mailgun(formData);
7
8export const mg = mailgun.client({
9 username: 'api',
10 key: process.env.MAILGUN_API_KEY || '',
11});
Step 5: Create Mailgun Templates
Because if you try to style it, chances are it's going to look like that carrier pigeon after it just flew into a windshield.π©Έ
Go to the Mailgun Templates page.
Create a new template called
contact-us
.Add variables like
{{name}}
,{{email}}
, and{{message}}
to personalize your email.
Here's an example:
Step 6: Create an API Route to Send Emails
If you are using the pages router in Next, it might look like the following. If not, then, you know, adjust it, to app router.
1// pages/api/contact-us.js
2
3import { mg } from '@/lib/mailgun';
4
5export default async function handler(req, res) {
6 if (req.method === 'POST') {
7 const { name, email, message } = req.body;
8
9 if (!name || !email || !message) {
10 return res.status(400).json({ message: 'Please provide all required fields.' });
11 }
12
13 const mailData = {
14 from: process.env.MAILGUN_FROM_DEFAULT,
15 to: 'support@yourdomain.com',
16 subject: `New message from ${name}`,
17 template: 'contact-us',
18 'h:X-Mailgun-Variables': JSON.stringify({ name, email, message }),
19 };
20
21 try {
22 await mg.messages.create(process.env.MAILGUN_DOMAIN, mailData);
23 res.status(200).json({ message: 'Email sent successfully.' });
24 } catch (error) {
25 console.error('Error sending email:', error);
26 res.status(500).json({ message: 'Failed to send email.' });
27 }
28 } else {
29 res.setHeader('Allow', 'POST');
30 res.status(405).end('Method Not Allowed');
31 }
32}
Step 7: Create a Contact Form
Zip over to the frontend to make the ugliest thing you've ever seen since the sensory homunculus.
1// pages/contact-us.js
2
3import { useState } from 'react';
4
5export default function ContactUs() {
6 const [form, setForm] = useState({ name: '', email: '', message: '' });
7 const [responseMessage, setResponseMessage] = useState('');
8
9 const handleSubmit = async (e) => {
10 e.preventDefault();
11
12 const response = await fetch('/api/contact-us', {
13 method: 'POST',
14 headers: { 'Content-Type': 'application/json' },
15 body: JSON.stringify(form),
16 });
17
18 const result = await response.json();
19 setResponseMessage(result.message);
20 };
21
22 return (
23 <div>
24 <h1>Contact Us</h1>
25 <form onSubmit={handleSubmit}>
26 <input
27 type="text"
28 placeholder="Your Name"
29 value={form.name}
30 onChange={(e) => setForm({ ...form, name: e.target.value })}
31 required
32 />
33 <input
34 type="email"
35 placeholder="Your Email"
36 value={form.email}
37 onChange={(e) => setForm({ ...form, email: e.target.value })}
38 required
39 />
40 <textarea
41 placeholder="Your Message"
42 value={form.message}
43 onChange={(e) => setForm({ ...form, message: e.target.value })}
44 required
45 ></textarea>
46 <button type="submit">Send Message</button>
47 </form>
48 <p>{responseMessage}</p>
49 </div>
50 );
51}
Step 8: Test Email Sending
Because nothing ever works the first time.
Add your personal email to the Mailgun Authorized Recipients list (if you're using a sandbox domain).
Fill out the contact form and submit.
Check your inbox. Spam folder counts too.
All done π
You've just integrated Mailgun into your Next.js app. Now your emails might actually reach someone's inbox instead of vanishing into wherever emails go to disappear.
Pair it with Stripe for purchase confirmations π
Mailgun and Stripe go hand in hand, and I've already set this up in a manner far more professional than how I write.
If you like time and money back in your pocket, check it out here.
If you want to see just how much TIME and MONEY it could save you, have a flick over this.
What's in the Box? π
π§ Mailgun Pre-Integrated: Start sending emails effortlessly.
π Tailwind CSS Styling: Make your app look like you hired a top-notch designer, minus the phat invoice.
πΈ Stripe Integration: Because your "brilliant" app that your mum wants to buy deserves to make money.
π₯ Firebase Backend: Authentication and real-time database included. Saving you days of work.
π‘ TypeScript Support: Catch errors before they become your nightmare at 3 AM.
π Storyblok CMS: Manage your content with ease and maybe even a smile.
And that's just the tip of the iceberg...
Want more?
Get notified about new posts and updates. No spam, I promise.
We will never share nor sell your details.