feat: added smtp support to email#342
feat: added smtp support to email#342arianpotter wants to merge 5 commits intoOpenpanel-dev:mainfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds SMTP as an alternative email delivery backend alongside Resend: updates env templates/examples and docs, adds server-side React Email rendering and Nodemailer deps, and implements conditional routing in ChangesEmail delivery (single cohesive change DAG)
Sequence Diagram(s)sequenceDiagram
participant App as Application
participant Email as sendEmail
participant Renderer as `@react-email/render`
participant SMTP as Nodemailer
participant Resend as Resend API
App->>Email: sendEmail(template, to, data)
Email->>Email: compute subject & unsubscribe headers
alt SMTP_HOST configured
Email->>Renderer: render template -> HTML
Renderer-->>Email: HTML
Email->>SMTP: transport.sendMail({from,to,subject,html,headers})
SMTP-->>Email: send result
else RESEND_API_KEY configured
Email->>Resend: resend.emails.send({... , subject, headers})
Resend-->>Email: send result
else No provider
Email-->>App: log to console, return null
end
Email-->>App: return send result
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/email/src/index.tsx (1)
76-85: Add a plain-text body for SMTP emails.The SMTP path currently sends only HTML.
@react-email/renderexportstoPlainTextto derive plain text from rendered HTML, which improves compatibility for clients that prefer or require text bodies.✉️ Proposed plain-text fallback
-import { render } from '@react-email/render'; +import { render, toPlainText } from '@react-email/render';const html = await render( <template.Component {...(props.data as any)} />, ); + const text = toPlainText(html); const transport = createSmtpTransport(); const res = await transport.sendMail({ from: FROM, to, subject, html, + text, headers, });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/email/src/index.tsx` around lines 76 - 85, The SMTP send currently only sets html; derive a plain-text body and include it in the sendMail call by importing and using toPlainText from `@react-email/render` to convert the rendered html into text, then pass that text as the text property to transport.sendMail (locate where render(...) produces html for template.Component and where createSmtpTransport() and transport.sendMail({...}) are called and add the text field).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/email/src/index.tsx`:
- Around line 18-27: The createSmtpTransport function can mis-handle an empty
SMTP_PORT (Number('') === 0) and lacks explicit timeouts; update
createSmtpTransport (where createTransport is called) to use a safe port parse
like: if process.env.SMTP_PORT is set use Number(process.env.SMTP_PORT)
otherwise default to 587, and add nodemailer timeout options (connectionTimeout,
greetingTimeout, socketTimeout) with sensible values to avoid long stalls; also
keep the existing auth logic and secure parsing as-is.
---
Nitpick comments:
In `@packages/email/src/index.tsx`:
- Around line 76-85: The SMTP send currently only sets html; derive a plain-text
body and include it in the sendMail call by importing and using toPlainText from
`@react-email/render` to convert the rendered html into text, then pass that text
as the text property to transport.sendMail (locate where render(...) produces
html for template.Component and where createSmtpTransport() and
transport.sendMail({...}) are called and add the text field).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0d780cc6-00cd-4d05-bb13-2c9ceaba19aa
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (4)
.env.examplepackages/email/package.jsonpackages/email/src/index.tsxself-hosting/.env.template
| EMAIL_SENDER="$EMAIL_SENDER" | ||
| # Option A - Resend | ||
| RESEND_API_KEY="$RESEND_API_KEY" | ||
| # Option B - SMTP (takes priority over Resend if SMTP_HOST is set) |
There was a problem hiding this comment.
does not make sense to add these here if we dont support it in out setup (self-hosting/quiz.ts)
There was a problem hiding this comment.
Sine I added the description to self-hosting.mdx (8229720)
does it make more sense? or shall we add it to the setup as well?
|
Thanks for the contribution, first of all, have you tested this locally? Also, could you add a section to our docs? First we could add the envs here https://github.com/Openpanel-dev/openpanel/blob/main/apps/public/content/docs/self-hosting/environment-variables.mdx and then we could add a little section here as well https://github.com/Openpanel-dev/openpanel/blob/main/apps/public/content/docs/self-hosting/self-hosting.mdx#e-mail |
|
why not merge the values SMTP_HOST, SMTP_PORT, SMTP_SECURE, SMTP_USER and SMTP_PASS to one variable? it would be string containing the URL and let it parse with standard URL where all necessary properties are present (https://developer.mozilla.org/en-US/docs/Web/API/URL)? |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/public/content/docs/self-hosting/environment-variables.mdx`:
- Around line 373-384: The docs for SMTP_USER must explicitly state that SMTP
authentication only occurs when both SMTP_USER and SMTP_PASS are set because in
packages/email/src/index.tsx the auth object is created only when the condition
SMTP_USER && SMTP_PASS is true; update the SMTP_USER section to note that
leaving SMTP_PASS unset (or vice versa) will silently disable authentication and
that both variables are required for authenticated SMTP connections.
- Around line 399-402: Update the existing Callout that mentions "SMTP takes
priority" to explicitly state that if SMTP_HOST is set and an SMTP send attempt
fails, the system will not automatically fall back to using RESEND_API_KEY
(emails may be silently dropped); mention that to use Resend instead either
unset SMTP_HOST or implement an application-level fallback/retry, and include
the SMTP_HOST and RESEND_API_KEY variable names in the note so readers can find
the relevant config.
In `@apps/public/content/docs/self-hosting/self-hosting.mdx`:
- Around line 137-139: Update the Callout to explicitly state that SMTP_HOST
takes precedence and that if the SMTP transport (see send function in
packages/email/src/index.tsx which returns null on error) fails during send, the
code does not fall back to Resend even if RESEND_API_KEY is set; add a single
clear sentence clarifying "no automatic Resend fallback on SMTP failure" and
reference SMTP_HOST and RESEND_API_KEY so readers know both variables won't
provide a backup transport in that failure case.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bb086453-9922-4411-b0dc-b5c55ae25e89
📒 Files selected for processing (2)
apps/public/content/docs/self-hosting/environment-variables.mdxapps/public/content/docs/self-hosting/self-hosting.mdx
3347986 to
db46fc8
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.env.example (1)
20-25: ⚡ Quick winAdd SMTP precedence note here for consistency.
Line 20 says “pick one”, but runtime behavior uses SMTP first when both are present. Adding that note here avoids operator confusion.
Suggested diff
-# EMAIL (pick one) +# EMAIL (pick one; SMTP takes priority if SMTP_HOST is set) # Option A - Resend # RESEND_API_KEY="" # EMAIL_SENDER="hello@openpanel.dev" # Option B - SMTP🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.example around lines 20 - 25, Update the .env.example comment block for the email configuration to clearly state that SMTP takes precedence when both options are set: reference the RESEND_API_KEY and SMTP_HOST/EMAIL_SENDER variables and modify the “pick one” text to indicate runtime behavior (SMTP will be used first if both RESEND and SMTP credentials are present), so operators understand which provider will be selected.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In @.env.example:
- Around line 20-25: Update the .env.example comment block for the email
configuration to clearly state that SMTP takes precedence when both options are
set: reference the RESEND_API_KEY and SMTP_HOST/EMAIL_SENDER variables and
modify the “pick one” text to indicate runtime behavior (SMTP will be used first
if both RESEND and SMTP credentials are present), so operators understand which
provider will be selected.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a304fa00-f0d6-4d0f-ab84-1719a6ae687d
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
.env.exampleapps/public/content/docs/self-hosting/environment-variables.mdxapps/public/content/docs/self-hosting/self-hosting.mdxpackages/email/package.jsonpackages/email/src/index.tsxself-hosting/.env.template
✅ Files skipped from review due to trivial changes (3)
- packages/email/package.json
- apps/public/content/docs/self-hosting/self-hosting.mdx
- apps/public/content/docs/self-hosting/environment-variables.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/email/src/index.tsx
db46fc8 to
8229720
Compare
Sorry for the late reaction. Yes I already have tested it locally with mailpit. |
It is not a bad idea in general. However, we add some room for error in case the password contains special characters. |
Add SMTP support as alternative to Resend (issue #320)
Overview
Email sending now supports two transports: SMTP (via nodemailer) and Resend. If
SMTP_HOSTis set, SMTP is used. Otherwise it falls back to Resend. If neither is configured, the email payload is logged to console (existing dev behavior).How it works
SMTP_HOST set? → render template to HTML → send via nodemailer
↓ no
RESEND_API_KEY set? → send via Resend (unchanged behavior)
↓ no
Log to console (dev fallback)
Implementation details
packages/email/src/index.tsx@react-email/renderto convert React Email JSX templates to plain HTML strings — required for SMTP since nodemailer doesn't understand JSXnodemailerfor SMTP transportcreateSmtpTransport()readsSMTP_HOST/PORT/SECURE/USER/PASSfrom envList-Unsubscribe) are preserved for both transportsNew dependencies
nodemailer+@types/nodemailer— SMTP client@react-email/render— HTML renderer for React Email templatesConfiguration
SMTP_HOSTSMTP_PORT587SMTP_SECUREfalse"true"for TLS (port 465)SMTP_USERSMTP_PASSEMAIL_SENDERhello@openpanel.devBoth
.env.exampleandself-hosting/.env.templatehave been updated with the new variables and comments explaining the two options.Summary by CodeRabbit
New Features
Configuration
Documentation