Skip to content

Commit

Permalink
add filter
Browse files Browse the repository at this point in the history
  • Loading branch information
mathe42 committed Mar 30, 2022
1 parent 00e5f73 commit 9660096
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 18 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ await client.send({
await client.close();
```

### Filter E-Mails
If you want a custom E-Mail validator and filter some E-Mails (because they are burner mails or the domain is on a blacklist or only allow specific domains etc.) you can add the `mailFilter` option to the smtp-client constructor options. `mailFilter` takes a function that gets 3 Arguments the "mailbox" (all that is before @ in the mail), the "domain" (what is after the @) and `internalTag` that is a new option that can be set in the mailConfig so you can set a type for that mail for example type `newsletter` etc. `internalTag` can be a `string` or a `symbol`.

The filter function returns a boolean or a Promise that resolves to a boolean. There are 3 things you can do when this function is called:

1. return `true` the E-Mail is keept in the list
2. return `false` the E-Mail is removed from the list
3. throw an Error the E-Mail is aborted and never send

So you can decide if a single mail error results in a complete mail abort or it only get removed from the list.

You can for example validate against this list: https://github.com/wesbos/burner-email-providers.


### Configuring your client

You can pass options to your client through the `SmtpClient` constructor.
Expand Down
1 change: 1 addition & 0 deletions config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface SendConfig {
references?: string;
priority?: "high" | "normal" | "low";
attachments?: attachment[];
internalTag?: string | symbol
}

interface baseAttachment {
Expand Down
70 changes: 52 additions & 18 deletions smtp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface Command {
interface SmtpClientOptions {
console_debug?: boolean;
unsecure?: boolean;
mailFilter?: (box: string, domain: string, internalTag?: string | symbol | undefined) => (Promise<boolean> | boolean)
}

export class SmtpClient {
Expand All @@ -33,13 +34,16 @@ export class SmtpClient {

#console_debug = false;
#allowUnsecure = false;
#mailFilter: SmtpClientOptions['mailFilter']

constructor({
console_debug = false,
unsecure = false,
mailFilter
}: SmtpClientOptions = {}) {
this.#console_debug = console_debug;
this.#allowUnsecure = unsecure;
this.#mailFilter = mailFilter
}

async connect(config: ConnectConfig | ConnectConfigWithAuthentication) {
Expand Down Expand Up @@ -104,7 +108,25 @@ export class SmtpClient {

const [from, fromData] = this.parseAddress(config.from);

const to = normaliceMailList(config.to).map((m) => this.parseAddress(m));
const to = config.to ? await this.filterMails(normaliceMailList(config.to).map((m) => this.parseAddress(m)), config.internalTag) : false;

const cc = config.cc
? await this.filterMails(normaliceMailList(config.cc).map((v) => this.parseAddress(v)), config.internalTag)
: false;

const bcc =config.bcc ? await this.filterMails(normaliceMailList(config.bcc).map((v) =>
this.parseAddress(v)
), config.internalTag) : false;

if (config.replyTo) {
config.replyTo = normaliceMailString(config.replyTo);

const res = await this.filterMail([config.replyTo, config.replyTo], config.internalTag)

if(!res) {
throw new Error("ReplyTo Email is not vaild as the filter returned false")
}
}

const date = config.date ??
new Date().toUTCString().split(",")[1].slice(1);
Expand Down Expand Up @@ -156,28 +178,22 @@ export class SmtpClient {
await this.writeCmd("MAIL", "FROM:", from);
this.assertCode(await this.readCmd(), CommandCode.OK);

for (let i = 0; i < to.length; i++) {
await this.writeCmd("RCPT", "TO:", to[i][0]);
this.assertCode(await this.readCmd(), CommandCode.OK);
if(to) {
for (let i = 0; i < to.length; i++) {
await this.writeCmd("RCPT", "TO:", to[i][0]);
this.assertCode(await this.readCmd(), CommandCode.OK);
}
}

const cc = config.cc
? normaliceMailList(config.cc).map((v) => this.parseAddress(v))
: false;

if (cc) {
console.log("cc");
for (let i = 0; i < cc.length; i++) {
await this.writeCmd("RCPT", "TO:", cc[i][0]);
this.assertCode(await this.readCmd(), CommandCode.OK);
}
}


if (config.bcc) {
const bcc = normaliceMailList(config.bcc).map((v) =>
this.parseAddress(v)
);

if (bcc) {
for (let i = 0; i < bcc.length; i++) {
await this.writeCmd("RCPT", "TO:", bcc[i][0]);
this.assertCode(await this.readCmd(), CommandCode.OK);
Expand All @@ -189,7 +205,9 @@ export class SmtpClient {

await this.writeCmd("Subject: ", config.subject);
await this.writeCmd("From: ", fromData);
await this.writeCmd("To: ", to.map((v) => v[1]).join(";"));
if(to) {
await this.writeCmd("To: ", to.map((v) => v[1]).join(";"));
}
if (cc) {
await this.writeCmd("Cc: ", cc.map((v) => v[1]).join(";"));
}
Expand All @@ -204,8 +222,6 @@ export class SmtpClient {
}

if (config.replyTo) {
config.replyTo = normaliceMailString(config.replyTo);

await this.writeCmd("ReplyTo: ", config.replyTo);
}

Expand Down Expand Up @@ -438,6 +454,24 @@ export class SmtpClient {
return [`<${m}>`, email];
} else {
return [`<${email}>`, `<${email}>`];
}
}
}

private async filterMail([raw, _withName]: [string, string], internalTag: string | symbol | undefined): Promise<boolean> {
if(!this.#mailFilter) return true

const [box, domain] = raw.slice(1, raw.length - 1).split('@')

const res = await this.#mailFilter!(box, domain, internalTag)

return res
}

private async filterMails(mails: [string, string][], internalTag: string | symbol | undefined): Promise<[string, string][]> {
if(!this.#mailFilter) return mails

const keep = await Promise.all(mails.map(m => this.filterMail(m, internalTag)))

return mails.filter((_, i) => keep[i])
}
}

0 comments on commit 9660096

Please sign in to comment.