email.send provides helpers for sending transactional emails from extension hooks and cron jobs. SMTP must be configured in
AppConfig before any email will be delivered. See SMTP Setup.
Built-in Helpers#
Each method sends one of the built-in templates. The first argument is an
EmailAddress, and table names the auth table the user belongs to:
email.send.verifyEmail(
EmailAddress(address: user.email),
table: 'users',
);
email.send.passwordReset(
EmailAddress(address: user.email),
table: 'users',
);
email.send.otpCode(
EmailAddress(address: user.email),
table: 'users',
);
loginNotice,magicLinkandconfirmEmailChangealso exist, but the server does not implement them yet. Calling one sends nothing and raises anUnimplementedErroron the server. The defaultonSignInhook callsloginNoticefor auth tables with an email column, so overrideonSignInto stop it. To send a sign-in notice today, useemail.send(Email(template: 'login_notice', ...)), as shown below.
All helpers accept an optional variables map to pass extra data to the template.
Sending Custom Emails#
Use email.send(Email(...)) to send a custom template:
email.send(Email(
to: EmailAddress(address: user.email),
subject: 'Your order is confirmed',
template: 'order_confirmation',
variables: {
'orderId': purchase.id,
'total': purchase.total,
'status': purchase.status,
},
));
The template field is the filename (without .html) from emailTemplatesPath. See
Custom Templates.
Threading#
Pass thread on multiple related emails (e.g. OTP resends) to group them in the user's inbox:
email.send(Email(
to: EmailAddress(address: user.email),
subject: 'New sign-in code',
template: 'otp_code',
variables: {'otp': newCode},
thread: Email.createThread('otp:users:${user.email}', continueThread: true),
));
When Email Sends#
email.send.* is fire-and-forget — it does not await delivery and does not block the HTTP response. If SMTP delivery fails, the error is logged but the original request still succeeds. There is no built-in retry.
Example#
import 'package:my_app/src/schemas/users.dart';
import 'package:zonai_schema/zonai_schema.dart';
final class UserExtensions extends Extension<User>
with AuthExtension<User> {
UserExtensions() : super(users);
@override
Future<void> onSignUp(User user, Jwt? jwt) async {
email.send.verifyEmail(
EmailAddress(address: user.email),
table: 'users',
);
}
@override
Future<void> onSignIn(User user, Jwt? jwt) async {
email.send(Email(
to: EmailAddress(address: user.email),
subject: 'New sign-in',
template: 'login_notice',
variables: {
'email': user.email,
'signedInAt': DateTime.now().toUtc().toIso8601String(),
},
));
}
}
UserExtensions main() => UserExtensions();