src/module/mail/mail.service.ts
Methods |
|
constructor(userService: UserService, settingsService: SettingsService, templateService: TemplateService)
|
||||||||||||
Defined in src/module/mail/mail.service.ts:29
|
||||||||||||
Parameters :
|
Private createSMTPTransport | ||||||||
createSMTPTransport(options: IMailingSettings)
|
||||||||
Defined in src/module/mail/mail.service.ts:195
|
||||||||
Parameters :
Returns :
Mail
A nodemail SMTPTransport instance created with the given options. |
Private generateMailingStatus | ||||||||
generateMailingStatus(promiseResults: PromiseSettledResult
|
||||||||
Defined in src/module/mail/mail.service.ts:120
|
||||||||
Converts the given promise results into a
Parameters :
Returns :
MailingStatus
|
Private getTextOfMail | ||||||||
getTextOfMail(user: User)
|
||||||||
Defined in src/module/mail/mail.service.ts:182
|
||||||||
Parameters :
Returns :
string
The mail template filled with the data of the given user |
Private isValidEmail | ||||||||
isValidEmail(email: string)
|
||||||||
Defined in src/module/mail/mail.service.ts:209
|
||||||||
Parameters :
Returns :
boolean
Is the string a valid email address? |
Async mailCredentials |
mailCredentials()
|
Defined in src/module/mail/mail.service.ts:43
|
Sends a mail with the credentials to all users. The mail is only sent to users which are not the 'admin' user and which did not already changed their initial password (ie still have a temporary password).
Returns :
Promise<MailingStatus>
Data containing information about the amount of successfully send mails and information about failed ones. |
Async mailSingleCredentials | ||||||
mailSingleCredentials(userId: string)
|
||||||
Defined in src/module/mail/mail.service.ts:81
|
||||||
Sends a mail with the credentials to the user with the given ID. The mail is only sent to the user if he/she has not already changed their initial password.
Parameters :
Returns :
Promise<MailingStatus>
Data containing information about the amount of successfully send mails (1) and information on failure. |
Private Async sendMail | |||||
sendMail(undefined: SendMailParams)
|
|||||
Defined in src/module/mail/mail.service.ts:165
|
|||||
Tries to send a mail with the credentials of the given user. If the mail was sent successfully a
Parameters :
Returns :
Promise<SentMessageInfo>
Info about the sent message. |
import { Injectable, InternalServerErrorException } from '@nestjs/common';
import nodemailer from 'nodemailer';
import Mail from 'nodemailer/lib/mailer';
import { SentMessageInfo } from 'nodemailer/lib/smtp-transport';
import { FailedMail, MailingStatus } from 'shared/model/Mail';
import { IMailingSettings } from 'shared/model/Settings';
import { getNameOfEntity } from 'shared/util/helpers';
import { User } from '../../database/entities/user.entity';
import { VALID_EMAIL_REGEX } from '../../helpers/validators/nodemailer.validator';
import { SettingsService } from '../settings/settings.service';
import { TemplateService } from '../template/template.service';
import { UserService } from '../user/user.service';
class MailingError {
constructor(
readonly userId: string,
readonly message: string,
readonly err: unknown
) {}
}
interface SendMailParams {
user: User;
transport: Mail;
options: IMailingSettings;
}
@Injectable()
export class MailService {
constructor(
private readonly userService: UserService,
private readonly settingsService: SettingsService,
private readonly templateService: TemplateService
) {}
/**
* Sends a mail with the credentials to all users.
*
* The mail is only sent to users which are not the 'admin' user and which did not already changed their initial password (ie still have a temporary password).
*
* @returns Data containing information about the amount of successfully send mails and information about failed ones.
*/
async mailCredentials(): Promise<MailingStatus> {
const options = await this.settingsService.getMailingOptions();
if (!options) {
throw new InternalServerErrorException('MISSING_MAIL_SETTINGS');
}
const transport = this.createSMTPTransport(options);
const usersToMail = (await this.userService.findAll()).filter(
(u) => u.username !== 'admin' && !!u.temporaryPassword
);
const mails: Promise<SentMessageInfo>[] = [];
const failedMails: FailedMail[] = [];
for (const user of usersToMail) {
if (this.isValidEmail(user.email)) {
mails.push(this.sendMail({ user, transport, options }));
} else {
failedMails.push({
userId: user.id,
reason: 'INVALID_EMAIL_ADDRESS',
});
}
}
const status = this.generateMailingStatus(await Promise.allSettled(mails));
transport.close();
return status;
}
/**
* Sends a mail with the credentials to the user with the given ID.
*
* The mail is only sent to the user if he/she has not already changed their initial password.
*
* @returns Data containing information about the amount of successfully send mails (1) and information on failure.
*/
async mailSingleCredentials(userId: string): Promise<MailingStatus> {
const options = await this.settingsService.getMailingOptions();
if (!options) {
throw new InternalServerErrorException('MISSING_MAIL_SETTINGS');
}
const transport = this.createSMTPTransport(options);
const user = await this.userService.findById(userId);
if (!user.temporaryPassword) {
return {
successFullSend: 0,
failedMailsInfo: [{ userId: user.id, reason: 'NO_TEMP_PWD_ON_USER' }],
};
}
if (!this.isValidEmail(user.email)) {
return {
successFullSend: 0,
failedMailsInfo: [{ userId: user.id, reason: 'INVALID_EMAIL_ADDRESS' }],
};
}
const status = await Promise.allSettled([this.sendMail({ user, transport, options })]);
transport.close();
return this.generateMailingStatus(status);
}
/**
* Converts the given promise results into a `MailingStatus` object extracting the important information:
*
* - Information about all failed ones.
* - Amount of successfully sent ones.
*
* @param promiseResults All promise results from settled promises sending mails.
* @returns `MailingStatus` according to the responses.
*/
private generateMailingStatus(
promiseResults: PromiseSettledResult<SentMessageInfo>[]
): MailingStatus {
const status: MailingStatus = {
failedMailsInfo: [],
successFullSend: 0,
};
for (const mail of promiseResults) {
if (mail.status === 'fulfilled') {
status.successFullSend += 1;
} else {
if (mail.reason instanceof MailingError) {
status.failedMailsInfo.push({
userId: mail.reason.userId,
reason: `${mail.reason.message}:\n${JSON.stringify(
mail.reason.err,
null,
2
)}`,
});
} else {
status.failedMailsInfo.push({
userId: 'UNKNOWN',
reason: 'UNKNOWN_ERROR',
});
}
}
}
return status;
}
/**
* Tries to send a mail with the credentials of the given user.
*
* If the mail was sent successfully a `SentMessageInfo` is returned. If it fails an error is thrown.
*
* @param user User to send the mail to
* @param options MailingConfiguration
* @param transport Transport to use.
*
* @returns Info about the sent message.
* @throws `MailingError` - If the mail could not be successfully send.
*/
private async sendMail({ user, options, transport }: SendMailParams): Promise<SentMessageInfo> {
try {
return await transport.sendMail({
from: options.from,
to: user.email,
subject: options.subject,
text: this.getTextOfMail(user),
});
} catch (err) {
throw new MailingError(user.id, 'SEND_MAIL_FAILED', err);
}
}
/**
* @param user User to get the mail text for.
* @returns The mail template filled with the data of the given user
*/
private getTextOfMail(user: User): string {
const template = this.templateService.getMailTemplate();
return template({
name: getNameOfEntity(user, { firstNameFirst: true }),
username: user.username,
password: user.temporaryPassword ?? 'NO_TMP_PASSWORD',
});
}
/**
* @param options Options to create the transport with.
* @returns A nodemail SMTPTransport instance created with the given options.
*/
private createSMTPTransport(options: IMailingSettings): Mail {
return nodemailer.createTransport({
host: options.host,
port: options.port,
auth: { user: options.auth.user, pass: options.auth.pass },
logger: true,
debug: true,
});
}
/**
* @param email String to check.
* @returns Is the string a valid email address?
*/
private isValidEmail(email: string): boolean {
return VALID_EMAIL_REGEX.test(email);
}
// private isOAuth2(auth: SMTPConnection.AuthenticationType): auth is AuthenticationTypeOAuth2 {
// return auth.type === 'oauth2' || auth.type === 'OAuth2' || auth.type === 'OAUTH2';
// }
// private isBasicAuth(auth: SMTPConnection.AuthenticationType): auth is AuthenticationTypeLogin {
// return !auth.type || auth.type === 'login' || auth.type === 'Login' || auth.type === 'LOGIN';
// }
}