From d5aa8d03bb805e2b6ab604d25b480cb4ce720e52 Mon Sep 17 00:00:00 2001 From: Chris Greenacre Date: Thu, 19 Mar 2026 09:46:10 +0000 Subject: [PATCH] Added email notifications for new accounts --- settings.toml.example | 2 ++ src/handlers/pdsSubscriber.ts | 11 ++++++++ src/mailer.ts | 47 +++++++++++++++++++++++++++++++++++ src/types/settings.ts | 1 + 4 files changed, 61 insertions(+) diff --git a/settings.toml.example b/settings.toml.example index 29afea3..7de255d 100644 --- a/settings.toml.example +++ b/settings.toml.example @@ -12,6 +12,8 @@ pdsAdminPassword = "secure" backfillAccounts = true # Listens for new accounts listenForNewAccounts = true +# Send notification for new accounts +notifyOnNewAccounts = false # Another PDS you want to watch # [pds.your-pds-two] diff --git a/src/handlers/pdsSubscriber.ts b/src/handlers/pdsSubscriber.ts index d6d3db4..8c88f22 100644 --- a/src/handlers/pdsSubscriber.ts +++ b/src/handlers/pdsSubscriber.ts @@ -6,6 +6,7 @@ import { logger } from "../logger.js"; import { FirehoseSubscription } from "@atcute/firehose"; import { ComAtprotoSyncSubscribeRepos } from "@atcute/atproto"; import { handleNewIdentityEvent } from "./handleNewIdentityEvent.js"; +import { sendNewAccountNotification } from "../mailer.js"; export const pdsSubscriber = ( config: PDSConfig, @@ -39,6 +40,16 @@ export const pdsSubscriber = ( }, "Identity event", ); + if (config.notifyOnNewAccounts) { + await queue.add(() => + sendNewAccountNotification(config.notifyEmails, { + did: message.did, + pds: config.host + }).catch((err) => { + logger.error({ err }, "Error sending new account notification email") + }) + ); + } await queue.add(() => handleNewIdentityEvent( db, diff --git a/src/mailer.ts b/src/mailer.ts index cadc5b0..c0414c5 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -73,6 +73,53 @@ export const getInfoFromParams = (params: { return info.join("\n"); } +export const sendNewAccountNotification = async ( + emails: string[], + params: { + did: string; + pds: string; + } +) => { + const { + did, + pds + } = params; + + const subject = `New account created on ${pds} - ${did}`; + let infoText = [ + `A new account has been detected on ${pds}.`, + ``, + `DID: ${did}`, + `PDS: ${pds}` + ]; + const emailText = infoText.join("\n"); + + if (resend) { + await resend.emails.send({ + from: senderEmail, + to: emails, + subject, + emailText, + }); + } else { + if (transporter) { + await transporter.sendMail({ + from: senderEmail, + to: emails.join(", "), + subject, + emailText, + }); + } else { + logger.error( + { + error: "No transporter available", + }, + "Error sending email", + ); + } + } +} + export const sendLabelNotification = async ( emails: string[], params: { diff --git a/src/types/settings.ts b/src/types/settings.ts index 75207ed..f3186f3 100644 --- a/src/types/settings.ts +++ b/src/types/settings.ts @@ -7,6 +7,7 @@ export interface PDSConfig { pdsAdminPassword?: string; backfillAccounts: boolean; listenForNewAccounts: boolean; + notifyOnNewAccounts: boolean; } export type LabelAction = "notify" | "takedown"; -- 2.51.2