toeverything/AFFiNE · error · EmailServiceNotConfigured
email_service_not_configured
email_service_not_configured
Error message
Email service is not configured.
What it means
EmailServiceNotConfigured (code=email_service_not_configured) thrown by Mailer.send when this.sender.configured is false and the caller did not pass suppressError. The mailer refuses to enqueue/attempt delivery because no SMTP/transactional provider is set up. When suppressError=true the call returns false instead.
Source
Thrown at packages/backend/server/src/core/mail/mailer.ts:96
recipientUserId: metadata.recipientUserId,
actorUserId: metadata.actorUserId,
workspaceId: metadata.workspaceId,
notificationId: metadata.notificationId,
abuseSubjectKey: metadata.abuseSubjectKey,
payload: serializePayload(command),
expiresAt: metadata.expiresAt,
maxAttempts: 0,
lastErrorCode: options.reason,
});
return false;
}
async send(command: MailCommand, suppressError = false) {
if (!this.sender.configured) {
if (suppressError) {
return false;
}
throw new EmailServiceNotConfigured();
}
let reservationId: string | undefined;
let deliveryId: string | undefined;
try {
const metadata = command.metadata ?? {};
const deduped = metadata.dedupeKey
? await this.models.mailDelivery.findByDedupeKey(metadata.dedupeKey)
: null;
if (deduped) {
return !['failed', 'canceled', 'skipped'].includes(deduped.status);
}
const decision = await this.runtime.assertMailDeliveryQuotaV1({
mailName: command.name as MailName,
recipient: {
email: command.to,
domain: recipientDomain(command.to),View on GitHub (pinned to 26c515e050)
Solutions
- Configure SMTP (or the configured transactional provider) in env and restart the server; verify sender.configured is true via the admin mail status endpoint.
- For non-critical mail paths, pass suppressError=true so the absence of mail degrades gracefully instead of failing the workflow.
- Gate mail-dependent features (invitations, verification) behind a 'mail configured' check in the UI.
- Add a startup warning/log when mail-dependent features are enabled but sender.configured is false.
Example fix
// before
async send(command: MailCommand, suppressError = false) {
if (!this.sender.configured) {
if (suppressError) return false;
throw new EmailServiceNotConfigured();
}
...
}
// caller side — pass suppressError for non-critical mail
await this.mailer.send(inviteMail, /* suppressError */ true); Defensive patterns
Strategy: validation
Validate before calling
async function assertMailConfigured(mailer) {
if (!mailer.sender.configured) {
throw new UserError('Email service is not configured');
}
} Type guard
function isEmailNotConfigured(e: unknown): boolean {
return e instanceof Error && (e as any).code === 'email_service_not_configured';
} Try / catch
// For non-critical mail, suppress; for critical, surface a clear message
try {
await mailer.send(mail);
} catch (e) {
if (isEmailNotConfigured(e)) {
return res.status(503).send('Email not configured on this server');
}
throw e;
}
// OR: await mailer.send(mail, /* suppressError */ true); Prevention
- Configure SMTP env before enabling mail-dependent features.
- Gate 'send invite' UI on a mail-configured flag.
- Use suppressError=true for non-critical mail so workflows don't break.
When it happens
Trigger: Any mail-sending path (verification, invitation, notification, test mail) invoked on a deployment where the mail sender has no valid configuration. The check is on sender.configured, which is false until SMTP host/credentials (or the transactional provider) are provided.
Common situations: Fresh self-hosted install without SMTP env vars set. Mail config removed/rotated and not reapplied. A feature that sends mail enabled while mail is unconfigured (invites on, SMTP off).
Related errors
AI-assisted analysis of toeverything/AFFiNE@26c515e050 (2026-08-12).
Data as JSON: /api/errors/4f01902a50ae3137.
Report an issue: GitHub.