Better Auth
Send Better Auth's verification, password reset, magic link, one-time code and invitation emails through coss.com.
Better Auth asks you for a function per email it sends. cossEmail
gives you all of them, with plain default templates you can replace one by one.
npm install coss better-authimport { } from "better-auth";
import { } from "coss/better-auth";
const = ({
: "Acme <auth@acme.com>",
: "Acme",
});
export const = ({
: {
: true,
: .,
},
: {
: true,
: .,
},
: {
: {
: true,
: .,
},
: {
: true,
: .,
},
},
});Plugins
The plugins that send email take the matching callback:
const = ({
: "Acme <auth@acme.com>",
: "Acme",
// Better Auth passes no link for invitations, so tell coss.com where invitees accept them.
: ({ }) => `https://acme.com/accept-invitation/${}`,
});
export const = ({
: [
({ : . }),
({ : . }),
({ : . }),
],
});| Callback | Better Auth option | Default subject |
|---|---|---|
sendVerificationEmail | emailVerification.sendVerificationEmail | Verify your email address |
sendResetPassword | emailAndPassword.sendResetPassword | Reset your password |
sendChangeEmailConfirmation | user.changeEmail.sendChangeEmailConfirmation | Confirm your new email address |
sendDeleteAccountVerification | user.deleteUser.sendDeleteAccountVerification | Confirm account deletion |
sendMagicLink | magicLink({ sendMagicLink }) | Sign in to appName |
sendVerificationOTP | emailOTP({ sendVerificationOTP }) | Depends on the code's purpose |
sendInvitationEmail | organization({ sendInvitationEmail }) | Join organization on appName |
Templates
Replace any template with your own. Each one gets the data Better Auth passed plus your appName,
and returns a subject and both bodies:
const = ({
: "Acme <auth@acme.com>",
: {
: ({ , }) => ({
: "Reset your Acme password",
: `<p>Hi ${. ?? "there"}, <a href="${}">choose a new password</a>.</p>`,
: `Hi ${. ?? "there"}, choose a new password: ${}`,
}),
},
});Escape anything user-controlled (names, organization names) in your own HTML. The default templates already do.
email.send({ to, subject, html, text }) sends any other email with the same sender and
defaults, and returns the email. Use it for things like a welcome email from a Better Auth hook.
Behaviour
- Emails go out with
category: "account"and open and click tracking off. Passcategoryto change the category. - Each email with a link derives its idempotency key from a hash of the link's token, so a callback that runs twice for the same token sends once. Codes and invitations can be legitimately resent with the same value, so they get a fresh key per send.
- Callbacks throw a
CossSendErrorwhen coss.com refuses the email.
Better Auth recommends not awaiting email sends, so response times don't reveal whether an account
exists (a timing attack). On serverless platforms, hand the promise to waitUntil so the send
still finishes:
export const = ({
: {
: true,
: async () => {
(.());
},
},
});