diff --git a/server/emails/mailer.tsx b/server/emails/mailer.tsx index f8f7eb8da..1c9186654 100644 --- a/server/emails/mailer.tsx +++ b/server/emails/mailer.tsx @@ -20,6 +20,7 @@ type SendMailOptions = { text: string; component: JSX.Element; headCSS?: string; + unsubscribeUrl?: string; }; /** @@ -94,6 +95,14 @@ export class Mailer { subject: data.subject, html, text: data.text, + list: data.unsubscribeUrl + ? { + unsubscribe: { + url: data.unsubscribeUrl, + comment: "Unsubscribe from these emails", + }, + } + : undefined, attachments: env.isCloudHosted() ? undefined : [ diff --git a/server/emails/templates/BaseEmail.tsx b/server/emails/templates/BaseEmail.tsx index 4477ec158..85f0d802d 100644 --- a/server/emails/templates/BaseEmail.tsx +++ b/server/emails/templates/BaseEmail.tsx @@ -12,7 +12,10 @@ export interface EmailProps { to: string | null; } -export default abstract class BaseEmail { +export default abstract class BaseEmail< + T extends EmailProps, + S extends Record +> { private props: T; private metadata?: NotificationMetadata; @@ -103,6 +106,7 @@ export default abstract class BaseEmail { ), text: this.renderAsText(data), headCSS: this.headCSS?.(data), + unsubscribeUrl: data.unsubscribeUrl, }); Metrics.increment("email.sent", { templateName, diff --git a/server/emails/templates/ConfirmUserDeleteEmail.tsx b/server/emails/templates/ConfirmUserDeleteEmail.tsx index d7123f04e..6aa467227 100644 --- a/server/emails/templates/ConfirmUserDeleteEmail.tsx +++ b/server/emails/templates/ConfirmUserDeleteEmail.tsx @@ -16,7 +16,10 @@ type Props = EmailProps & { /** * Email sent to a user when they request to delete their account. */ -export default class ConfirmUserDeleteEmail extends BaseEmail { +export default class ConfirmUserDeleteEmail extends BaseEmail< + Props, + Record +> { protected subject() { return `Your account deletion request`; } diff --git a/server/emails/templates/ExportFailureEmail.tsx b/server/emails/templates/ExportFailureEmail.tsx index ea5b06232..037786f2b 100644 --- a/server/emails/templates/ExportFailureEmail.tsx +++ b/server/emails/templates/ExportFailureEmail.tsx @@ -24,7 +24,10 @@ type BeforeSendProps = { /** * Email sent to a user when their data export has failed for some reason. */ -export default class ExportFailureEmail extends BaseEmail { +export default class ExportFailureEmail extends BaseEmail< + Props, + BeforeSendProps +> { protected async beforeSend({ userId }: Props) { return { unsubscribeUrl: NotificationSettingsHelper.unsubscribeUrl( diff --git a/server/emails/templates/ExportSuccessEmail.tsx b/server/emails/templates/ExportSuccessEmail.tsx index 2f9aac5ef..fbf7886f5 100644 --- a/server/emails/templates/ExportSuccessEmail.tsx +++ b/server/emails/templates/ExportSuccessEmail.tsx @@ -27,7 +27,10 @@ type BeforeSendProps = { * Email sent to a user when their data export has completed and is available * for download in the settings section. */ -export default class ExportSuccessEmail extends BaseEmail { +export default class ExportSuccessEmail extends BaseEmail< + Props, + BeforeSendProps +> { protected async beforeSend({ userId }: Props) { return { unsubscribeUrl: NotificationSettingsHelper.unsubscribeUrl( diff --git a/server/emails/templates/InviteAcceptedEmail.tsx b/server/emails/templates/InviteAcceptedEmail.tsx index 737b618c8..20b769cac 100644 --- a/server/emails/templates/InviteAcceptedEmail.tsx +++ b/server/emails/templates/InviteAcceptedEmail.tsx @@ -25,7 +25,10 @@ type BeforeSendProps = { /** * Email sent to a user when someone they invited successfully signs up. */ -export default class InviteAcceptedEmail extends BaseEmail { +export default class InviteAcceptedEmail extends BaseEmail< + Props, + BeforeSendProps +> { protected async beforeSend({ inviterId }: Props) { return { unsubscribeUrl: NotificationSettingsHelper.unsubscribeUrl( diff --git a/server/emails/templates/InviteEmail.tsx b/server/emails/templates/InviteEmail.tsx index 2f1248c18..ab4a41f05 100644 --- a/server/emails/templates/InviteEmail.tsx +++ b/server/emails/templates/InviteEmail.tsx @@ -20,7 +20,7 @@ type Props = EmailProps & { /** * Email sent to an external user when an admin sends them an invite. */ -export default class InviteEmail extends BaseEmail { +export default class InviteEmail extends BaseEmail> { protected subject({ actorName, teamName }: Props) { return `${actorName} invited you to join ${teamName}’s knowledge base`; } diff --git a/server/emails/templates/InviteReminderEmail.tsx b/server/emails/templates/InviteReminderEmail.tsx index df40d15ec..c509391b9 100644 --- a/server/emails/templates/InviteReminderEmail.tsx +++ b/server/emails/templates/InviteReminderEmail.tsx @@ -21,7 +21,10 @@ type Props = EmailProps & { * Email sent to an external user when an admin sends them an invite and they * haven't signed in after a few days. */ -export default class InviteReminderEmail extends BaseEmail { +export default class InviteReminderEmail extends BaseEmail< + Props, + Record +> { protected subject({ actorName, teamName }: Props) { return `Reminder: ${actorName} invited you to join ${teamName}’s knowledge base`; } diff --git a/server/emails/templates/SigninEmail.tsx b/server/emails/templates/SigninEmail.tsx index 172acd6d8..453e525ac 100644 --- a/server/emails/templates/SigninEmail.tsx +++ b/server/emails/templates/SigninEmail.tsx @@ -20,7 +20,7 @@ type Props = EmailProps & { /** * Email sent to a user when they request a magic sign-in link. */ -export default class SigninEmail extends BaseEmail { +export default class SigninEmail extends BaseEmail> { protected subject() { return "Magic signin link"; } diff --git a/server/emails/templates/WebhookDisabledEmail.tsx b/server/emails/templates/WebhookDisabledEmail.tsx index 357d6d4f5..785bafd39 100644 --- a/server/emails/templates/WebhookDisabledEmail.tsx +++ b/server/emails/templates/WebhookDisabledEmail.tsx @@ -17,7 +17,10 @@ type Props = EmailProps & { * Email sent to the creator of a webhook when the webhook has become disabled * due to repeated failure. */ -export default class WebhookDisabledEmail extends BaseEmail { +export default class WebhookDisabledEmail extends BaseEmail< + Props, + Record +> { protected subject() { return `Warning: Webhook disabled`; } diff --git a/server/emails/templates/WelcomeEmail.tsx b/server/emails/templates/WelcomeEmail.tsx index a1ebef228..d65d472a3 100644 --- a/server/emails/templates/WelcomeEmail.tsx +++ b/server/emails/templates/WelcomeEmail.tsx @@ -17,7 +17,10 @@ type Props = EmailProps & { * Email sent to a user when their account has just been created, or they signed * in for the first time from an invite. */ -export default class WelcomeEmail extends BaseEmail { +export default class WelcomeEmail extends BaseEmail< + Props, + Record +> { protected subject() { return `Welcome to ${env.APP_NAME}`; }