Better Auth
Learn how to send Better Auth verification and password reset emails using Mailtrap's Email API.
Overview
This guide explains how to integrate Mailtrap with Better Auth to deliver the emails your authentication flows depend on, such as email verification links and password reset tokens.
Better Auth does not send email itself. It calls a function you provide, so you decide which provider delivers the message. This guide implements that function with the Mailtrap Email API.
Better Auth sends email from several places. Core email and password authentication uses two callbacks, and some plugins add their own:
Email verification
emailVerification.sendVerificationEmail
Password reset
emailAndPassword.sendResetPassword
Magic Link plugin
magicLink({ sendMagicLink })
Email OTP plugin
emailOTP({ sendVerificationOTP })
Organization plugin
organization({ sendInvitationEmail })
All of them are plain async functions, so a single sendEmail helper can serve every one.
Prerequisites
Before you start, make sure you have:
An existing Better Auth project
Installation
Install the Mailtrap Node.js SDK:
Send emails using Better Auth and Mailtrap
First, create a reusable sendEmail function backed by the Mailtrap Email API:
Then pass it to Better Auth to handle email verification and password resets:
Plugin emails
If you use the Magic Link, Email OTP, or Organization plugins, reuse the same sendEmail helper for their callbacks. Add the plugins array to the same betterAuth call shown above, keeping only the plugins your app actually uses:
Configuration
Once you copy the scripts, update the following:
Set
MAILTRAP_API_KEYin your environment to your Mailtrap API tokenReplace
no-reply@yourdomain.comwith an address on your verified sending domainReplace
Your Appwith the sender name you want recipients to seeReplace
https://yourdomain.comin the invitation link with your app's base URL
The category field is optional. Setting it per email type lets you filter authentication emails in Email Logs and see the category on delivery webhooks, so you can tell reset emails from verification emails at a glance.
The link-based examples send both html and text. The HTML version gives recipients a clickable link, and the plain text version is a fallback for clients that do not render HTML. The one-time code is plain text only, since there is nothing to link to.
Escape every user-controlled value you interpolate into an html body. The invitation example runs the organization name through escapeHtml because whoever created the organization chose that name: left raw, a name containing </a><a href="..."> closes your link and opens theirs, so the email arrives from your verified domain carrying an attacker's URL. That makes it a convincing phishing message, and invitations are the worst case because Better Auth sends them to people who are not users yet and have no way to judge what is normal for your app.
Watch for this anywhere the value is not authored by you, including display names, team and organization names, and any custom note attached to an invitation. Escaping is only needed for html; text and subject are not parsed as markup, which is why the examples leave them as they are.
For richer, designed emails, keep the markup out of your application code and use Email Templates instead. Templates need a different payload, so add a separate helper rather than reusing sendEmail:
Mailtrap renders the template, so the variables are passed as data and do not need HTML escaping.
Learn more
For additional details about the Email API, refer to the Mailtrap Email Sending API Integration guide and the Mailtrap Node.js SDK.
Last updated
Was this helpful?

