Emails

Enterprise-grade email system with Vue Email templates and multi-provider support. Switch between Resend, SES, Mailgun, or custom SMTP without changing code.

After trying various email setups in Nuxt, I finally landed on what I think is the perfect combination: AdonisJS Mail + Vue Email. It gives you the flexibility to switch between any email provider without rewriting code, and you get to write your templates in Vue.

What's Included

I've set up all the essential emails you need for a SaaS:

  • Welcome emails when users sign up
  • Magic link authentication (what this site uses)
  • Email verification flows
  • Password reset emails
  • Team invitations
  • And more templates you can customize

The best part? Everything just works out of the box with any email provider you prefer—Resend, AWS SES, Mailgun, or even custom SMTP.

The Basic Setup

Here's how the configuration looks:

~/utils/emails.ts
const config: Parameters<typeof generateMailer>[0] = {
  default: "resend",
  from: {
    address: "hi@saas-boilerplate.dev",
    name: "Tanay Karnik",
  },
  replyTo: {
    address: "hi@saas-boilerplate.dev",
    name: "Tanay Karnik",
  },
  mailers: {
    resend: transports.resend({
      baseUrl: "https://api.resend.com",
      key: process.env.RESEND_API_KEY || "",
    }),
    // Easily configure other providers
    mailgun: transports.mailgun({
      baseUrl: "https://api.mailgun.net/v3",
      key: process.env.MAILGUN_API_KEY || "",
      domain: process.env.MAILGUN_DOMAIN || "",
    }),
  },
};

Writing Email Templates

Templates are built using Vue Email components with Tailwind CSS support for consistent styling:

<template>
  <Tailwind>
    <Html>
    <Head />
    <Body class="bg-white my-auto mx-auto font-sans">
      <Container class="p-4 border border-solid border-[#eaeaea] rounded my-[40px] mx-auto max-w-[465px]">
        <Section class="mt-[32px]">
          <Img src="https://saas-boilerplate.dev/pwa-64x64.png" alt="SaaS Boilerplate" class="my-0 mx-auto" />
        </Section>
        <Heading class="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
          Welcome
        </Heading>
        <Text class="text-black text-[14px] leading-[24px]">
          Hi {{ username }},
        </Text>
        <Text class="text-black text-[14px] leading-[24px]">
          Welcome aboard! We're excited to have you join us.
        </Text>
        <Text class="text-black text-[14px] leading-[24px]">
          If you have any questions, please don't hesitate to reach out.
        </Text>
      </Container>
    </Body>
    </Html>
  </Tailwind>
</template>

<script setup lang="ts">
import {
  Body,
  Container,
  Head,
  Heading,
  Html,
  Img,
  Section,
  Text,
} from "@vue-email/components";
import { Tailwind } from "@vue-email/tailwind";

interface Props {
  username?: string;
}

withDefaults(defineProps<Props>(), {
  username: "User",
});
</script>

Screenshot for Magic Link Sign In

Sending Emails

Sending emails is straightforward:

import WelcomeEmail from "~/emails/WelcomeEmail.vue";

const mailer = await getMailer();
await mailer.send(async (message) => {
  message
    .to(user.email)
    .subject("Welcome to Our Platform!")
    .html(
      await render(WelcomeEmail, {
        username: user.name,
      })
    );
});

Cool Features from AdonisJS Mail

AdonisJS Mail (view documentation) comes with tons of powerful features that we can use:

  1. Multiple Transport Support: Switch between email providers with one line of code
  2. Calendar Events: Attach calendar invites to your emails
  3. File Attachments: Easily attach files, streams, or buffers
  4. HTML/Text Templates: Support for both HTML and plain text emails

For example, attaching a calendar invite is as simple as:

message.icalEvent((calendar) => {
  calendar.createEvent({
    summary: 'Team Meeting',
    start: DateTime.local().plus({ minutes: 30 }),
    end: DateTime.local().plus({ minutes: 60 }),
  })
});

Handling CC and BCC is simple:

message
  .to('primary@example.com')
  .cc(['teammate1@example.com', 'teammate2@example.com'])
  .bcc('archives@example.com');

A Few Tips

  1. Always use environment variables for your API keys
  2. Break down common email elements into reusable components
  3. Include plain text versions of your emails
  4. Test your emails across different clients

Need Help?

See It in Action

Want to see it in action? This site uses the exact same email system. Try the magic link sign-in to see one of the templates!