Skip to main content
Better Email is an open-source plugin that brings unified email management to Better Auth. Instead of configuring emails in 8+ places, you can centralize everything: one provider, one renderer, lifecycle hooks, and type-safe templates.

Why Better Email?

When implementing Better Auth with full email features, you typically need to configure email callbacks in multiple locations: email verification, password resets, magic links, two-factor codes, organization invitations, and more. Each callback requires its own configuration and email logic. Better Email consolidates all these callbacks into a single, unified interface with:
  • One provider configuration for all email types
  • Swappable providers (Nuntly, …)
  • Swappable renderers (React Email, MJML, Mustache, plain HTML)
  • Type-safe templates with TypeScript validation
  • Lifecycle hooks for logging and error handling
  • Consistent tag management across all email types

Installation

npm install @nuntly/better-email

Quick start with Nuntly provider

import { betterAuth } from 'better-auth';
import { betterEmail } from '@nuntly/better-email';
import { NuntlyProvider } from '@nuntly/better-email/providers/nuntly';
import { ReactEmailRenderer } from '@nuntly/better-email/renderers/react-email';
import { render } from '@react-email/components';
import { createElement } from 'react';

const email = betterEmail({
  provider: new NuntlyProvider({
    apiKey: process.env.NUNTLY_API_KEY!,
    from: 'auth@yourapp.com',
  }),
  templateRenderer: new ReactEmailRenderer({
    render,
    createElement,
    templates: {
      'verification-email': VerificationEmail,
      'reset-password': ResetPasswordEmail,
      'magic-link': MagicLinkEmail,
      'verification-otp': OTPEmail,
      'organization-invitation': InvitationEmail,
      'change-email-verification': ChangeEmailEmail,
      'delete-account-verification': DeleteAccountEmail,
      'two-factor-otp': TwoFactorOTPEmail,
    },
    subjects: {
      'verification-email': 'Verify your email',
      'reset-password': 'Reset your password',
      'magic-link': 'Your sign-in link',
      'verification-otp': 'Your verification code',
      'organization-invitation': (ctx) => `Join ${ctx.organization.name}`,
      'change-email-verification': 'Confirm email change',
      'delete-account-verification': 'Confirm account deletion',
      'two-factor-otp': 'Your two-factor code',
    },
  }),
});

export const auth = betterAuth({
  emailVerification: {
    sendOnSignUp: true,
  },
  emailAndPassword: {
    enabled: true,
  },
  plugins: [
    email,
    twoFactor({ sendOTP: email.helpers.twoFactor }),
    organization({ sendInvitationEmail: email.helpers.invitation }),
    magicLink({ sendMagicLink: email.helpers.magicLink }),
    emailOTP({ sendVerificationOTP: email.helpers.otp }),
  ],
});

Available providers

Better Email supports multiple email providers out of the box:

Nuntly

Production-ready email delivery with tracking and analytics

Resend

Modern email API for developers

Postmark

Transactional email service

Mailgun

Email delivery and validation

SES

Email service from Amazon Web Services

SMTP

Standard SMTP protocol support

Console

Development mode logging

Available renderers

Choose the template renderer that fits your stack:
  • React Email: Use React components for email templates
  • React MJML: Combine React with MJML for responsive emails
  • MJML: Responsive email markup language
  • Mustache: Logic-less template engine
  • Default HTML: Simple HTML string templates

Lifecycle hooks

Apply consistent logging and error handling across all email types:
const email = betterEmail({
  provider: new NuntlyProvider({
    /* ... */
  }),
  templateRenderer: new ReactEmailRenderer({
    /* ... */
  }),
  onBeforeSend: async (ctx, msg) => {
    console.log(`Preparing ${ctx.type} email to ${msg.to}`);
  },
  onAfterSend: async (ctx, msg) => {
    console.log(`Sent ${ctx.type} to ${msg.to}`);
  },
  onSendError: async (ctx, msg, err) => {
    console.error(`Failed to send ${ctx.type}:`, err);
  },
});

Tag management

Add default tags to every email for analytics and filtering:
const email = betterEmail({
  provider: new NuntlyProvider({
    /* ... */
  }),
  templateRenderer: new ReactEmailRenderer({
    /* ... */
  }),
  defaultTags: [
    { name: 'app', value: 'yourapp' },
    { name: 'environment', value: process.env.NODE_ENV },
  ],
});
Every email automatically gets a { name: 'type', value: ctx.type } tag for filtering by email type.

Custom renderers

Implement the EmailTemplateRenderer interface for custom template rendering:
import { EmailTemplateRenderer, BetterAuthEmailContext } from '@nuntly/better-email';

class CustomRenderer implements EmailTemplateRenderer {
  async render(context: BetterAuthEmailContext): Promise<{ subject: string; html: string; text?: string }> {
    // Your custom rendering logic
  }
}

Learn more

Getting your Nuntly API key

To use Better Email with the Nuntly provider, you need an API key:
  1. Sign up for a Nuntly account
  2. Complete the account setup
  3. Create an API key with send permissions
  4. Add your sending domain
Once configured, Better Email will handle all Better Auth email delivery through Nuntly with tracking, webhooks, and analytics built in.