1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

fix: send email on process.nextTick (#805)

To avoid users having to wait while we wait for a response from the email provider, we now send the mail on nextTick
This commit is contained in:
Christopher Kolstad 2021-04-27 09:05:46 +02:00 committed by GitHub
parent 33782d15d5
commit 0de4c98a58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 72 additions and 16 deletions

View File

@ -7,6 +7,7 @@ import { handleErrors } from './util';
import { IUnleashConfig } from '../../types/option'; import { IUnleashConfig } from '../../types/option';
import { EmailService, MAIL_ACCEPTED } from '../../services/email-service'; import { EmailService, MAIL_ACCEPTED } from '../../services/email-service';
import ResetTokenService from '../../services/reset-token-service'; import ResetTokenService from '../../services/reset-token-service';
import { IUnleashServices } from '../../types/services';
const getCreatorUsernameOrPassword = req => req.user.username || req.user.email; const getCreatorUsernameOrPassword = req => req.user.username || req.user.email;
@ -23,7 +24,18 @@ export default class UserAdminController extends Controller {
constructor( constructor(
config: IUnleashConfig, config: IUnleashConfig,
{ userService, accessService, emailService, resetTokenService }, {
userService,
accessService,
emailService,
resetTokenService,
}: Pick<
IUnleashServices,
| 'userService'
| 'accessService'
| 'emailService'
| 'resetTokenService'
>,
) { ) {
super(config); super(config);
this.userService = userService; this.userService = userService;

View File

@ -22,11 +22,10 @@ test('Can send reset email', async t => {
'test@resetLinkUrl.com', 'test@resetLinkUrl.com',
resetLinkUrl, resetLinkUrl,
); );
const message = JSON.parse(content.message); t.is(content.from, 'noreply@getunleash.ai');
t.is(message.from.address, 'noreply@getunleash.ai'); t.is(content.subject, 'Unleash - Reset your password');
t.is(message.subject, 'Unleash - Reset your password'); t.true(content.html.includes(resetLinkUrl));
t.true(message.html.includes(resetLinkUrl)); t.true(content.text.includes(resetLinkUrl));
t.true(message.text.includes(resetLinkUrl));
}); });
test('Can send welcome mail', async t => { test('Can send welcome mail', async t => {
@ -46,7 +45,6 @@ test('Can send welcome mail', async t => {
'test@test.com', 'test@test.com',
'abc123456', 'abc123456',
); );
const message = JSON.parse(content.message); t.is(content.from, 'noreply@getunleash.ai');
t.is(message.from.address, 'noreply@getunleash.ai'); t.is(content.subject, 'Welcome to Unleash');
t.is(message.subject, 'Welcome to Unleash');
}); });

View File

@ -30,6 +30,14 @@ export interface IEmailOptions {
transporterType: TransporterType; transporterType: TransporterType;
} }
export interface IEmailEnvelope {
from: string;
to: string;
subject: string;
html: string;
text: string;
}
const RESET_MAIL_SUBJECT = 'Unleash - Reset your password'; const RESET_MAIL_SUBJECT = 'Unleash - Reset your password';
const GETTING_STARTED_SUBJECT = 'Welcome to Unleash'; const GETTING_STARTED_SUBJECT = 'Welcome to Unleash';
@ -38,7 +46,7 @@ export const MAIL_ACCEPTED = '250 Accepted';
export class EmailService { export class EmailService {
private logger: Logger; private logger: Logger;
private mailer?: Transporter; private readonly mailer?: Transporter;
private readonly sender: string; private readonly sender: string;
@ -67,7 +75,7 @@ export class EmailService {
name: string, name: string,
recipient: string, recipient: string,
resetLink: string, resetLink: string,
): Promise<SentMessageInfo> { ): Promise<IEmailEnvelope> {
if (this.configured()) { if (this.configured()) {
const year = new Date().getFullYear(); const year = new Date().getFullYear();
const bodyHtml = await this.compileTemplate( const bodyHtml = await this.compileTemplate(
@ -95,13 +103,32 @@ export class EmailService {
html: bodyHtml, html: bodyHtml,
text: bodyText, text: bodyText,
}; };
return this.mailer.sendMail(email); process.nextTick(() => {
this.mailer.sendMail(email).then(
() =>
this.logger.info(
'Successfully sent reset-password email',
),
e =>
this.logger.warn(
'Failed to send reset-password email',
e,
),
);
});
return Promise.resolve(email);
} }
return new Promise(res => { return new Promise(res => {
this.logger.warn( this.logger.warn(
'No mailer is configured. Please read the docs on how to configure an emailservice', 'No mailer is configured. Please read the docs on how to configure an emailservice',
); );
res({}); res({
from: this.sender,
to: recipient,
subject: RESET_MAIL_SUBJECT,
html: '',
text: '',
});
}); });
} }
@ -109,7 +136,7 @@ export class EmailService {
name: string, name: string,
recipient: string, recipient: string,
passwordLink: string, passwordLink: string,
): Promise<SentMessageInfo> { ): Promise<IEmailEnvelope> {
if (this.configured()) { if (this.configured()) {
const year = new Date().getFullYear(); const year = new Date().getFullYear();
const context = { passwordLink, name, year }; const context = { passwordLink, name, year };
@ -130,13 +157,32 @@ export class EmailService {
html: bodyHtml, html: bodyHtml,
text: bodyText, text: bodyText,
}; };
return this.mailer.sendMail(email); process.nextTick(() => {
this.mailer.sendMail(email).then(
() =>
this.logger.info(
'Successfully sent getting started email',
),
e =>
this.logger.warn(
'Failed to send getting started email',
e,
),
);
});
return Promise.resolve(email);
} }
return new Promise(res => { return new Promise(res => {
this.logger.warn( this.logger.warn(
'No mailer is configured. Please read the docs on how to configure an EmailService', 'No mailer is configured. Please read the docs on how to configure an EmailService',
); );
res({}); res({
from: this.sender,
to: recipient,
subject: GETTING_STARTED_SUBJECT,
html: '',
text: '',
});
}); });
} }