Skip to content

Commit

Permalink
feat: support email configuration in payload config (#2485)
Browse files Browse the repository at this point in the history
* feat: support email configuration in payload config

* feat: set email defaults if no email config

* chore: leftover line from testing

* feat: add warning if email configure in both init and config
  • Loading branch information
denolfe authored Apr 17, 2023
1 parent f9b8e2d commit 042e58e
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export default joi.object({
}),
webpack: joi.func(),
}),
email: joi.object(),
i18n: joi.object(),
defaultDepth: joi.number()
.min(0)
Expand Down
8 changes: 8 additions & 0 deletions src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,14 @@ export type Config = {
* @see https://payloadcms.com/docs/configuration/globals#global-configs
*/
globals?: GlobalConfig[];

/**
* Email configuration options. This value is overridden by `email` in Payload.init if passed.
*
* @see https://payloadcms.com/docs/email/overview
*/
email?: EmailOptions;

/**
* Control the behaviour of the admin internationalisation.
*
Expand Down
14 changes: 9 additions & 5 deletions src/email/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ async function handleTransport(transport: Transporter, email: EmailTransport, lo
return { ...email, transport };
}

const ensureConfigHasFrom = (emailConfig) => {
if (!emailConfig.fromName || !emailConfig.fromAddress) {
const ensureConfigHasFrom = (emailConfig: EmailOptions) => {
if (!emailConfig?.fromName || !emailConfig?.fromAddress) {
throw new InvalidConfiguration('Email fromName and fromAddress must be configured when transport is configured');
}
};
Expand All @@ -28,19 +28,23 @@ const handleMockAccount = async (emailConfig: EmailOptions, logger: Logger) => {
try {
mockAccount = await mockHandler(emailConfig);
const { account: { web, user, pass } } = mockAccount;
if (emailConfig.logMockCredentials) {
if (emailConfig?.logMockCredentials) {
logger.info('E-mail configured with mock configuration');
logger.info(`Log into mock email provider at ${web}`);
logger.info(`Mock email account username: ${user}`);
logger.info(`Mock email account password: ${pass}`);
}
} catch (err) {
logger.error('There was a problem setting up the mock email handler', err);
logger.error({ msg: 'There was a problem setting up the mock email handler', err });
}
return mockAccount;
};

export default async function buildEmail(emailConfig: EmailOptions, logger: Logger): BuildEmailResult {
export default async function buildEmail(emailConfig: EmailOptions | undefined, logger: Logger): BuildEmailResult {
if (!emailConfig) {
return handleMockAccount(emailConfig, logger);
}

if (hasTransport(emailConfig) && emailConfig.transport) {
ensureConfigHasFrom(emailConfig);
const email = { ...emailConfig };
Expand Down
6 changes: 6 additions & 0 deletions src/email/defaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { EmailOptions } from '../config/types';

export const defaults: EmailOptions = {
fromName: 'Payload CMS',
fromAddress: '[email protected]',
};
6 changes: 4 additions & 2 deletions src/email/mockHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import nodemailer from 'nodemailer';
import { EmailOptions } from '../config/types';
import { MockEmailHandler } from './types';

import { defaults as emailDefaults } from './defaults';

const mockEmailHandler = async (emailConfig: EmailOptions): Promise<MockEmailHandler> => {
const testAccount = await nodemailer.createTestAccount();

Expand All @@ -10,8 +12,8 @@ const mockEmailHandler = async (emailConfig: EmailOptions): Promise<MockEmailHan
host: 'smtp.ethereal.email',
port: 587,
secure: false,
fromName: emailConfig.fromName || 'Payload CMS',
fromAddress: emailConfig.fromAddress || '[email protected]',
fromName: emailConfig?.fromName || emailDefaults.fromName,
fromAddress: emailConfig?.fromAddress || emailDefaults.fromAddress,
auth: {
user: testAccount.user,
pass: testAccount.pass,
Expand Down
9 changes: 8 additions & 1 deletion src/payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ import Logger from './utilities/logger';
import PreferencesModel from './preferences/model';
import findConfig from './config/find';

import { defaults as emailDefaults } from './email/defaults';

/**
* @description Payload
*/
Expand Down Expand Up @@ -160,7 +162,6 @@ export class BasePayload<TGeneratedTypes extends GeneratedTypes> {
throw new Error('Error: missing MongoDB connection URL.');
}

this.emailOptions = { ...(options.email) };
this.secret = crypto
.createHash('sha256')
.update(options.secret)
Expand Down Expand Up @@ -188,6 +189,12 @@ export class BasePayload<TGeneratedTypes extends GeneratedTypes> {
}

// Configure email service
const emailOptions = options.email ? { ...(options.email) } : this.config.email;
if (options.email && this.config.email) {
this.logger.warn('Email options provided in both init options and config. Using init options.');
}

this.emailOptions = emailOptions ?? emailDefaults;
this.email = buildEmail(this.emailOptions, this.logger);
this.sendEmail = sendEmail.bind(this);

Expand Down

0 comments on commit 042e58e

Please sign in to comment.