-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add email support with MJML and nunjucks engine (or just plain …
…text)
- Loading branch information
Showing
19 changed files
with
1,130 additions
and
88 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import type { Class } from 'type-fest' | ||
import { REFLECT_METADATA } from '../types/enums' | ||
|
||
export function email(target: Class, propertyKey: string, parameterIndex: number): void { | ||
Reflect.defineMetadata(REFLECT_METADATA.EMAIL, parameterIndex, target, propertyKey) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import type { GenericControllerInstance, InjectorFunctionParameter } from '../../types/interfaces' | ||
|
||
import { AbstractAction } from './AbstractAction' | ||
import { REFLECT_METADATA } from '../../types/enums' | ||
|
||
export class EmailAction extends AbstractAction { | ||
public run(instance: GenericControllerInstance, method: string): InjectorFunctionParameter { | ||
if (!Reflect.hasMetadata(REFLECT_METADATA.EMAIL, instance, method)) { | ||
return | ||
} | ||
|
||
const metadata = Reflect.getMetadata(REFLECT_METADATA.EMAIL, instance, method) as number | ||
|
||
return { | ||
index: metadata, | ||
value: this.injector.context.getEmailFactory(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import type { EmailTemplates } from '../types/types' | ||
import type { Transport } from 'nodemailer' | ||
import { config } from '../config/config' | ||
import { createTransport } from 'nodemailer' | ||
import { log } from '../log/logger' | ||
import mjml2html from 'mjml' | ||
import { renderString } from 'nunjucks' | ||
|
||
export class EmailFactory { | ||
protected transporter: Transport | null | ||
|
||
constructor(protected emailTemplates: EmailTemplates) { | ||
if (typeof config.email?.host === 'string') { | ||
this.transporter = (createTransport(config.email) as unknown) as Transport | ||
} else { | ||
this.transporter = null | ||
} | ||
} | ||
public send({ | ||
to = config.email.defaults.to, | ||
cc = config.email.defaults.cc, | ||
bcc = config.email.defaults.bcc, | ||
from = config.email.defaults.from, | ||
topic = config.email.defaults.topic, | ||
template, | ||
payload = {}, | ||
engine = config.email.engine, | ||
}: { | ||
to: string | ||
from?: string | ||
cc?: string | ||
bcc?: string | ||
topic: string | ||
template: string | ||
payload?: Record<string, unknown> | ||
engine?: string | ||
}): void { | ||
if (this.transporter === null) { | ||
log.warn( | ||
'Trying to send an E-Mail without proper email configuration. Please configure at least a email host', | ||
) | ||
|
||
return | ||
} else if (!this.emailTemplates.has(template)) { | ||
throw new Error(`Email template "${template}" not found!`) | ||
} | ||
|
||
let content = this.emailTemplates.get(template) | ||
|
||
if (engine !== 'plain') { | ||
content = renderString(content, payload) | ||
} | ||
|
||
if (engine === 'mjml') { | ||
const result = mjml2html(content, config.email?.mjml) | ||
|
||
if (result.errors.length) { | ||
log.error(result.errors) | ||
|
||
throw new Error('Failed to render MJML! See error(s) above for more information.') | ||
} | ||
|
||
content = result.html | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import type { EmailTemplates } from '../types/types' | ||
import { config } from '../config/config' | ||
import { fs } from '../filesystem/FS' | ||
import { parse } from 'path' | ||
import { promises } from 'fs' | ||
|
||
export class EmailTemplateLoader { | ||
public async load(): Promise<EmailTemplates> { | ||
const emailTemplates = new Map() as EmailTemplates | ||
const emailFilesPath = fs.resolveZenPath('email') | ||
|
||
if (!((await fs.exists(emailFilesPath)) || config.email.engine === 'plain')) { | ||
return emailTemplates | ||
} | ||
|
||
const filePaths = await this.loadFiles(emailFilesPath) | ||
|
||
for (const filePath of filePaths) { | ||
const { name } = parse(filePath) | ||
const content = await promises.readFile(filePath, { | ||
encoding: 'utf-8', | ||
}) | ||
|
||
emailTemplates.set(name, content) | ||
} | ||
|
||
return emailTemplates | ||
} | ||
protected async loadFiles(emailFilesPath: string): Promise<string[]> { | ||
const fileExtension = config.email.engine === 'mjml' ? '.mjml' : `.${config.template.extension}` | ||
|
||
return (await fs.readDir(emailFilesPath)).filter((filePath: string) => | ||
filePath.endsWith(fileExtension), | ||
) | ||
} | ||
} |
Oops, something went wrong.