mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
* feat: update n8n-users-list to no longer use preset list of actions * feat: prepared users settings for invite links feature * refactor: Return invite link URLs when inviting users (#5079) * refactor: Return invite link URLs when inviting users * test: Refactor and add tests to mailer * feat: Add FE inviteAcceptUrl integration (#5085) * feat: update n8n-users-list to no longer use preset list of actions * feat: prepared users settings for invite links feature * feat: add integration with new inviteAcceptUrl changes * feat: Add inviteAcceptUrl to user list for pending users Co-authored-by: Alex Grozav <alex@grozav.com> * fix conflicts * fix lint issue * test: Make sure inviteAcceptUrl is defined * feat: update smtp setup suggestion * feat: add invite link summary when inviting multiple users * refactor: Add telemetry flag for when email is sent * fix: add email_sent correctly to telemetry event * feat: move SMTP info-tip to invite modal Co-authored-by: Omar Ajoue <krynble@gmail.com>
96 lines
2.8 KiB
TypeScript
96 lines
2.8 KiB
TypeScript
import { existsSync } from 'fs';
|
|
import { readFile } from 'fs/promises';
|
|
import Handlebars from 'handlebars';
|
|
import { join as pathJoin } from 'path';
|
|
import * as GenericHelpers from '@/GenericHelpers';
|
|
import config from '@/config';
|
|
import {
|
|
InviteEmailData,
|
|
PasswordResetData,
|
|
SendEmailResult,
|
|
UserManagementMailerImplementation,
|
|
} from './Interfaces';
|
|
import { NodeMailer } from './NodeMailer';
|
|
|
|
type Template = HandlebarsTemplateDelegate<unknown>;
|
|
type TemplateName = 'invite' | 'passwordReset';
|
|
|
|
const templates: Partial<Record<TemplateName, Template>> = {};
|
|
|
|
async function getTemplate(
|
|
templateName: TemplateName,
|
|
defaultFilename = `${templateName}.html`,
|
|
): Promise<Template> {
|
|
let template = templates[templateName];
|
|
if (!template) {
|
|
const templateOverride = (await GenericHelpers.getConfigValue(
|
|
`userManagement.emails.templates.${templateName}`,
|
|
)) as string;
|
|
|
|
let markup;
|
|
if (templateOverride && existsSync(templateOverride)) {
|
|
markup = await readFile(templateOverride, 'utf-8');
|
|
} else {
|
|
markup = await readFile(pathJoin(__dirname, `templates/${defaultFilename}`), 'utf-8');
|
|
}
|
|
template = Handlebars.compile(markup);
|
|
templates[templateName] = template;
|
|
}
|
|
return template;
|
|
}
|
|
|
|
export class UserManagementMailer {
|
|
private mailer: UserManagementMailerImplementation | undefined;
|
|
|
|
constructor() {
|
|
// Other implementations can be used in the future.
|
|
if (
|
|
config.getEnv('userManagement.emails.mode') === 'smtp' &&
|
|
config.getEnv('userManagement.emails.smtp.host') !== ''
|
|
) {
|
|
this.mailer = new NodeMailer();
|
|
}
|
|
}
|
|
|
|
async verifyConnection(): Promise<void> {
|
|
if (!this.mailer) throw new Error('No mailer configured.');
|
|
|
|
return this.mailer.verifyConnection();
|
|
}
|
|
|
|
async invite(inviteEmailData: InviteEmailData): Promise<SendEmailResult> {
|
|
const template = await getTemplate('invite');
|
|
const result = await this.mailer?.sendMail({
|
|
emailRecipients: inviteEmailData.email,
|
|
subject: 'You have been invited to n8n',
|
|
body: template(inviteEmailData),
|
|
});
|
|
|
|
// If mailer does not exist it means mail has been disabled.
|
|
// No error, just say no email was sent.
|
|
return result ?? { emailSent: false };
|
|
}
|
|
|
|
async passwordReset(passwordResetData: PasswordResetData): Promise<SendEmailResult> {
|
|
const template = await getTemplate('passwordReset');
|
|
const result = await this.mailer?.sendMail({
|
|
emailRecipients: passwordResetData.email,
|
|
subject: 'n8n password reset',
|
|
body: template(passwordResetData),
|
|
});
|
|
|
|
// If mailer does not exist it means mail has been disabled.
|
|
// No error, just say no email was sent.
|
|
return result ?? { emailSent: false };
|
|
}
|
|
}
|
|
|
|
let mailerInstance: UserManagementMailer | undefined;
|
|
|
|
export function getInstance(): UserManagementMailer {
|
|
if (mailerInstance === undefined) {
|
|
mailerInstance = new UserManagementMailer();
|
|
}
|
|
return mailerInstance;
|
|
}
|