-
Notifications
You must be signed in to change notification settings - Fork 13
Add support for template-based emails in sendEmail function #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: seth/to-arrays
Are you sure you want to change the base?
Conversation
commit: |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the ✨ Finishing touches🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. Comment |
f55f45c to
a37df33
Compare
src/component/schema.ts
Outdated
| templateId: v.optional(v.string()), | ||
| templateVariables: v.optional(v.string()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| templateId: v.optional(v.string()), | |
| templateVariables: v.optional(v.string()), | |
| template: v.optional(vTemplate), |
ianmacartney
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
other than the vTemplate change, lgtm
src/component/lib.ts
Outdated
| if (email.templateId) { | ||
| payload.template = { | ||
| id: email.templateId, | ||
| variables: email.templateVariables | ||
| ? JSON.parse(email.templateVariables) | ||
| : {}, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (email.templateId) { | |
| payload.template = { | |
| id: email.templateId, | |
| variables: email.templateVariables | |
| ? JSON.parse(email.templateVariables) | |
| : {}, | |
| }; | |
| if (email.template) { | |
| payload.template = email.template; |
| if (email.subject) { | ||
| payload.subject = email.subject; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw one way to set fields only if they exist is to use the pick helper from convex-helpers like payload = { ...pick(email, ["from", "bcc", "cc", "subject", "template"]
src/component/lib.ts
Outdated
| throw new Error("Either html or text must be provided"); | ||
| // We require either html/text or a template to be provided. | ||
| const hasContent = args.html !== undefined || args.text !== undefined; | ||
| const hasTemplate = args.templateId !== undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const hasTemplate = args.templateId !== undefined; | |
| const hasTemplate = args.template?.id !== undefined; |
src/component/lib.ts
Outdated
| templateId: v.optional(v.string()), | ||
| templateVariables: v.optional(v.string()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| templateId: v.optional(v.string()), | |
| templateVariables: v.optional(v.string()), | |
| template: v.optional(vTemplate), |
src/client/index.ts
Outdated
| templateId?: string; | ||
| templateVariables?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| templateId?: string; | |
| templateVariables?: string; | |
| template?: Template; |
src/client/index.ts
Outdated
| if ("template" in sendEmailArgs) { | ||
| // Template-based email | ||
| const id = await ctx.runMutation(this.component.lib.sendEmail, { | ||
| options: await configToRuntimeConfig(this.config, this.onEmailEvent), | ||
| from: sendEmailArgs.from, | ||
| to: | ||
| typeof sendEmailArgs.to === "string" | ||
| ? [sendEmailArgs.to] | ||
| : sendEmailArgs.to, | ||
| cc: toArray(sendEmailArgs.cc), | ||
| bcc: toArray(sendEmailArgs.bcc), | ||
| subject: sendEmailArgs.subject, | ||
| replyTo: sendEmailArgs.replyTo, | ||
| headers: sendEmailArgs.headers, | ||
| templateId: sendEmailArgs.template.id, | ||
| templateVariables: JSON.stringify(sendEmailArgs.template.variables), | ||
| }); | ||
| return id as EmailId; | ||
| } else { | ||
| // Traditional email | ||
| const id = await ctx.runMutation(this.component.lib.sendEmail, { | ||
| options: await configToRuntimeConfig(this.config, this.onEmailEvent), | ||
| from: sendEmailArgs.from, | ||
| to: | ||
| typeof sendEmailArgs.to === "string" | ||
| ? [sendEmailArgs.to] | ||
| : sendEmailArgs.to, | ||
| cc: toArray(sendEmailArgs.cc), | ||
| bcc: toArray(sendEmailArgs.bcc), | ||
| replyTo: sendEmailArgs.replyTo, | ||
| headers: sendEmailArgs.headers, | ||
| subject: sendEmailArgs.subject, | ||
| html: sendEmailArgs.html, | ||
| text: sendEmailArgs.text, | ||
| }); | ||
| return id as EmailId; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm biased towards keeping both and adding template, since we'll be validating having the right fields anyways, and if they're specifying html and template it's probably better to fail than silently omit the html here, wdyt?
src/client/index.ts
Outdated
| if ("template" in sendEmailArgs) { | ||
| // Template-based email | ||
| const id = await ctx.runMutation(this.component.lib.sendEmail, { | ||
| options: await configToRuntimeConfig(this.config, this.onEmailEvent), | ||
| from: sendEmailArgs.from, | ||
| to: | ||
| typeof sendEmailArgs.to === "string" | ||
| ? [sendEmailArgs.to] | ||
| : sendEmailArgs.to, | ||
| cc: toArray(sendEmailArgs.cc), | ||
| bcc: toArray(sendEmailArgs.bcc), | ||
| subject: sendEmailArgs.subject, | ||
| replyTo: sendEmailArgs.replyTo, | ||
| headers: sendEmailArgs.headers, | ||
| templateId: sendEmailArgs.template.id, | ||
| templateVariables: JSON.stringify(sendEmailArgs.template.variables), | ||
| }); | ||
| return id as EmailId; | ||
| } else { | ||
| // Traditional email | ||
| const id = await ctx.runMutation(this.component.lib.sendEmail, { | ||
| options: await configToRuntimeConfig(this.config, this.onEmailEvent), | ||
| from: sendEmailArgs.from, | ||
| to: | ||
| typeof sendEmailArgs.to === "string" | ||
| ? [sendEmailArgs.to] | ||
| : sendEmailArgs.to, | ||
| cc: toArray(sendEmailArgs.cc), | ||
| bcc: toArray(sendEmailArgs.bcc), | ||
| replyTo: sendEmailArgs.replyTo, | ||
| headers: sendEmailArgs.headers, | ||
| subject: sendEmailArgs.subject, | ||
| html: sendEmailArgs.html, | ||
| text: sendEmailArgs.text, | ||
| }); | ||
| return id as EmailId; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if ("template" in sendEmailArgs) { | |
| // Template-based email | |
| const id = await ctx.runMutation(this.component.lib.sendEmail, { | |
| options: await configToRuntimeConfig(this.config, this.onEmailEvent), | |
| from: sendEmailArgs.from, | |
| to: | |
| typeof sendEmailArgs.to === "string" | |
| ? [sendEmailArgs.to] | |
| : sendEmailArgs.to, | |
| cc: toArray(sendEmailArgs.cc), | |
| bcc: toArray(sendEmailArgs.bcc), | |
| subject: sendEmailArgs.subject, | |
| replyTo: sendEmailArgs.replyTo, | |
| headers: sendEmailArgs.headers, | |
| templateId: sendEmailArgs.template.id, | |
| templateVariables: JSON.stringify(sendEmailArgs.template.variables), | |
| }); | |
| return id as EmailId; | |
| } else { | |
| // Traditional email | |
| const id = await ctx.runMutation(this.component.lib.sendEmail, { | |
| options: await configToRuntimeConfig(this.config, this.onEmailEvent), | |
| from: sendEmailArgs.from, | |
| to: | |
| typeof sendEmailArgs.to === "string" | |
| ? [sendEmailArgs.to] | |
| : sendEmailArgs.to, | |
| cc: toArray(sendEmailArgs.cc), | |
| bcc: toArray(sendEmailArgs.bcc), | |
| replyTo: sendEmailArgs.replyTo, | |
| headers: sendEmailArgs.headers, | |
| subject: sendEmailArgs.subject, | |
| html: sendEmailArgs.html, | |
| text: sendEmailArgs.text, | |
| }); | |
| return id as EmailId; | |
| } | |
| options: await configToRuntimeConfig(this.config, this.onEmailEvent), | |
| ...sendEmailArgs, | |
| to: | |
| typeof sendEmailArgs.to === "string" | |
| ? [sendEmailArgs.to] | |
| : sendEmailArgs.to, | |
| cc: toArray(sendEmailArgs.cc), | |
| bcc: toArray(sendEmailArgs.bcc), | |
| }); | |
| return id as EmailId; |
the only risk here is that passing extra args will fail -but in some ways that's a good thing
- Introduced `sendWithTemplate` action to handle sending emails with templates. - Updated `sendEmail` function to accept both traditional and template-based email formats. - Enhanced validation to ensure either content or template is provided, but not both. - Added tests for template email functionality, including acceptance and rejection scenarios. - Updated schema and shared types to include template-related fields.
a37df33 to
f6e46f0
Compare
sendWithTemplateaction to handle sending emails with templates.sendEmailfunction to accept both traditional and template-based email formats.Fixes issue #44