0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-02-24 22:05:56 -05:00

fix(connector): fix misuse of replyTo field (#7062)

fix(connector): fix miss use of replyTo field

fix the miss use of replyTo field. Should not be used as the alias of to email
This commit is contained in:
simeng-li 2025-02-24 17:54:50 +08:00 committed by GitHub
parent f15602f198
commit 84cc1ba523
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 22 additions and 28 deletions

View file

@ -258,13 +258,13 @@ describe('Maligun connector', () => {
to: 'bar@example.com', to: 'bar@example.com',
subject: 'Passcode 123456', subject: 'Passcode 123456',
html: '<p>Your passcode is 123456</p>', html: '<p>Your passcode is 123456</p>',
'h:Reply-To': 'Reply to bar@example.com', 'h:Reply-To': 'Reply to foo@email.com',
}); });
getI18nEmailTemplate.mockResolvedValue({ getI18nEmailTemplate.mockResolvedValue({
subject: 'Passcode {{code}}', subject: 'Passcode {{code}}',
content: '<p>Your passcode is {{code}}</p>', content: '<p>Your passcode is {{code}}</p>',
replyTo: 'Reply to {{to}}', replyTo: 'Reply to {{user.primaryEmail}}',
} satisfies EmailTemplateDetails); } satisfies EmailTemplateDetails);
getConfig.mockResolvedValue({ getConfig.mockResolvedValue({
@ -281,7 +281,7 @@ describe('Maligun connector', () => {
await connector.sendMessage({ await connector.sendMessage({
to: 'bar@example.com', to: 'bar@example.com',
type: TemplateType.Generic, type: TemplateType.Generic,
payload: { code: '123456' }, payload: { code: '123456', user: { primaryEmail: 'foo@email.com' } },
}); });
}); });
@ -292,15 +292,15 @@ describe('Maligun connector', () => {
subject: 'Passcode 123456', subject: 'Passcode 123456',
html: 'Your passcode is 123456', html: 'Your passcode is 123456',
text: 'Your passcode is 123456', text: 'Your passcode is 123456',
'h:Reply-To': 'Reply to bar@example.com', 'h:Reply-To': 'Reply to {{user.primaryEmail}}',
}); });
getI18nEmailTemplate.mockResolvedValue({ getI18nEmailTemplate.mockResolvedValue({
subject: 'Passcode {{code}}', subject: 'Passcode {{code}}',
content: 'Your passcode is {{code}}', content: 'Your passcode is {{code}}',
replyTo: 'Reply to {{to}}', replyTo: 'Reply to {{user.primaryEmail}}',
contentType: 'text/plain', contentType: 'text/plain',
sendFrom: `{{applicationName}} <${baseConfig.from}>`, sendFrom: `{{application.name}} <${baseConfig.from}>`,
} satisfies EmailTemplateDetails); } satisfies EmailTemplateDetails);
getConfig.mockResolvedValue({ getConfig.mockResolvedValue({
@ -309,7 +309,7 @@ describe('Maligun connector', () => {
[TemplateType.Generic]: { [TemplateType.Generic]: {
subject: 'Verification code is {{code}}', subject: 'Verification code is {{code}}',
html: '<p>Your verification code is {{code}}</p>', html: '<p>Your verification code is {{code}}</p>',
replyTo: 'baz@example.com', replyTo: 'no-reply@mail.com',
}, },
}, },
}); });
@ -317,7 +317,7 @@ describe('Maligun connector', () => {
await connector.sendMessage({ await connector.sendMessage({
to: 'bar@example.com', to: 'bar@example.com',
type: TemplateType.Generic, type: TemplateType.Generic,
payload: { code: '123456', applicationName: 'Foo' }, payload: { code: '123456', application: { name: 'Foo' } },
}); });
}); });
}); });

View file

@ -81,10 +81,7 @@ const sendMessage = (
const template = deliveries[type] ?? deliveries[TemplateType.Generic]; const template = deliveries[type] ?? deliveries[TemplateType.Generic];
const data = customTemplate const data = customTemplate
? getDataFromCustomTemplate(customTemplate, { ? getDataFromCustomTemplate(customTemplate, payload)
...payload,
to,
})
: // Fallback to the default template if the custom i18n template is not found. : // Fallback to the default template if the custom i18n template is not found.
template && getDataFromDeliveryConfig(template, payload); template && getDataFromDeliveryConfig(template, payload);

View file

@ -89,12 +89,11 @@ describe('SendGrid connector', () => {
subject: 'Passcode {{code}}', subject: 'Passcode {{code}}',
content: '<p>Your passcode is {{code}}</p>', content: '<p>Your passcode is {{code}}</p>',
contentType: 'text/html', contentType: 'text/html',
sendFrom: '{{applicationName}}', sendFrom: '{{application.name}}',
replyTo: '{{userName}}',
}); });
nockMessages({ nockMessages({
personalizations: [{ to: [{ email: toEmail, name: 'John Doe' }] }], personalizations: [{ to: [{ email: toEmail }] }],
from: { email: fromEmail, name: 'Test app' }, from: { email: fromEmail, name: 'Test app' },
subject: 'Passcode 123456', subject: 'Passcode 123456',
content: [ content: [
@ -112,8 +111,7 @@ describe('SendGrid connector', () => {
type: TemplateType.Generic, type: TemplateType.Generic,
payload: { payload: {
code: '123456', code: '123456',
applicationName: 'Test app', application: { name: 'Test app' },
userName: 'John Doe',
}, },
}); });
}); });

View file

@ -47,7 +47,7 @@ const buildParametersFromDefaultTemplate = (
const buildParametersFromCustomTemplate = ( const buildParametersFromCustomTemplate = (
to: string, to: string,
config: SendGridMailConfig, config: SendGridMailConfig,
{ subject, content, replyTo, sendFrom, contentType = 'text/html' }: EmailTemplateDetails, { subject, content, sendFrom, contentType = 'text/html' }: EmailTemplateDetails,
payload: SendMessagePayload payload: SendMessagePayload
): PublicParameters => { ): PublicParameters => {
return { return {
@ -56,8 +56,7 @@ const buildParametersFromCustomTemplate = (
to: [ to: [
{ {
email: to, email: to,
// If replyTo is provided, we will replace the handlebars with the payload ...conditional(config.fromName && { name: config.fromName }),
...conditional(replyTo && { name: replaceSendMessageHandlebars(replyTo, payload) }),
}, },
], ],
}, },

View file

@ -167,8 +167,8 @@ describe('Test SMTP connector with custom i18n templates', () => {
subject: 'Custom subject {{code}}', subject: 'Custom subject {{code}}',
content: 'Your verification code is {{code}}', content: 'Your verification code is {{code}}',
contentType: 'text/plain', contentType: 'text/plain',
replyTo: `{{userName}}`, replyTo: `{{user.primaryEmail}}`,
sendFrom: `{{applicationName}} <notice@test.smtp>`, sendFrom: `{{application.name}} <notice@test.smtp>`,
} satisfies EmailTemplateDetails); } satisfies EmailTemplateDetails);
const connector = await createConnector({ getConfig, getI18nEmailTemplate }); const connector = await createConnector({ getConfig, getI18nEmailTemplate });
@ -176,7 +176,11 @@ describe('Test SMTP connector with custom i18n templates', () => {
await connector.sendMessage({ await connector.sendMessage({
to: 'bar', to: 'bar',
type: TemplateType.SignIn, type: TemplateType.SignIn,
payload: { code: '234567', userName: 'John Doe', applicationName: 'Test app' }, payload: {
code: '234567',
user: { primaryEmail: 'test@email.com' },
application: { name: 'Test app' },
},
}); });
expect(sendMail).toHaveBeenCalledWith({ expect(sendMail).toHaveBeenCalledWith({
@ -184,7 +188,7 @@ describe('Test SMTP connector with custom i18n templates', () => {
subject: 'Custom subject 234567', subject: 'Custom subject 234567',
text: 'Your verification code is 234567', text: 'Your verification code is 234567',
to: 'bar', to: 'bar',
replyTo: 'John Doe', replyTo: 'test@email.com',
}); });
}); });
}); });

View file

@ -14,16 +14,12 @@ export type EmailTemplateDetails = {
* OPTIONAL: Custom replyTo template. * OPTIONAL: Custom replyTo template.
* *
* Based on the email client, the replyTo field may be used to customize the reply-to field of the email. * Based on the email client, the replyTo field may be used to customize the reply-to field of the email.
* @remarks
* The original reply email value can be found in the template variables.
*/ */
replyTo?: string; replyTo?: string;
/** /**
* OPTIONAL: Custom from template. * OPTIONAL: Custom from template.
* *
* Based on the email client, the sendFrom field may be used to customize the from field of the email. * Based on the email client, the sendFrom field may be used to customize the from field of the email.
* @remarks
* The sender email value can be found in the template variables.
*/ */
sendFrom?: string; sendFrom?: string;
}; };