From ea1238b1d1b225030fee8b357550479789cf1484 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Fri, 17 Apr 2026 13:59:50 -0600 Subject: [PATCH] feat: resend verification email on sign-in and improve email template - Add `sendOnSignIn: true` to emailVerification config so unverified users receive a new verification email when they attempt to sign in - Create styled verification email template matching the invoice email design - Extract `sendVerificationEmail` helper to keep auth.ts clean - Show friendly message on login when email is not verified --- apps/dokploy/pages/index.tsx | 10 ++ .../server/src/emails/emails/verify-email.tsx | 104 ++++++++++++++++++ packages/server/src/lib/auth.ts | 16 +-- .../verification/send-verification-email.tsx | 25 +++++ 4 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 packages/server/src/emails/emails/verify-email.tsx diff --git a/apps/dokploy/pages/index.tsx b/apps/dokploy/pages/index.tsx index aab788ad9..426c6c0a9 100644 --- a/apps/dokploy/pages/index.tsx +++ b/apps/dokploy/pages/index.tsx @@ -82,6 +82,16 @@ export default function Home({ IS_CLOUD }: Props) { }); if (error) { + const isEmailNotVerified = + error.code === "EMAIL_NOT_VERIFIED" || + error.message?.toLowerCase().includes("email not verified"); + if (isEmailNotVerified) { + const msg = + "Your email is not verified. We've sent a new verification link to your email."; + toast.info(msg); + setError(msg); + return; + } toast.error(error.message); setError(error.message || "An error occurred while logging in"); return; diff --git a/packages/server/src/emails/emails/verify-email.tsx b/packages/server/src/emails/emails/verify-email.tsx new file mode 100644 index 000000000..3a32db77d --- /dev/null +++ b/packages/server/src/emails/emails/verify-email.tsx @@ -0,0 +1,104 @@ +import { + Body, + Button, + Container, + Head, + Heading, + Html, + Img, + Link, + Preview, + Section, + Tailwind, + Text, +} from "@react-email/components"; + +export type TemplateProps = { + userName: string; + verificationUrl: string; +}; + +export const VerifyEmailTemplate = ({ + userName = "User", + verificationUrl = "https://app.dokploy.com/verify", +}: TemplateProps) => { + const previewText = "Verify your email address to get started with Dokploy"; + return ( + + + {previewText} + + + + {/* Header */} +
+ Dokploy +
+ + {/* Body */} +
+ + Verify Your Email + + + Hello {userName}, thank you for signing up for Dokploy. Please + verify your email address to activate your account. + + + {/* CTA Button */} +
+ +
+ + + If the button above doesn't work, copy and paste the following + link into your browser: + + + {verificationUrl} + +
+ + {/* Footer */} +
+ + This is an automated email from{" "} + + Dokploy Cloud + + . If you didn't create an account, you can safely ignore this + email. + +
+
+ +
+ + ); +}; + +export default VerifyEmailTemplate; diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index a4cc2f729..d6753dee6 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -21,7 +21,10 @@ import { updateWebServerSettings, } from "../services/web-server-settings"; import { getHubSpotUTK, submitToHubSpot } from "../utils/tracking/hubspot"; -import { sendEmail } from "../verification/send-verification-email"; +import { + sendEmail, + sendVerificationEmail, +} from "../verification/send-verification-email"; import { getPublicIpWithFallback } from "../wss/utils"; import { ac, adminRole, memberRole, ownerRole } from "./access-control"; @@ -73,7 +76,7 @@ const { handler, api } = betterAuth({ }, }, logger: { - disabled: process.env.NODE_ENV === "production", + disabled: false, }, async trustedOrigins() { try { @@ -106,14 +109,13 @@ const { handler, api } = betterAuth({ emailVerification: { sendOnSignUp: true, autoSignInAfterVerification: true, + sendOnSignIn: true, sendVerificationEmail: async ({ user, url }) => { if (IS_CLOUD) { - await sendEmail({ + await sendVerificationEmail({ + userName: user.name || "User", email: user.email, - subject: "Verify your email", - text: ` -

Click the link to verify your email: Verify Email

- `, + verificationUrl: url, }); } }, diff --git a/packages/server/src/verification/send-verification-email.tsx b/packages/server/src/verification/send-verification-email.tsx index d446e4b72..098789a2b 100644 --- a/packages/server/src/verification/send-verification-email.tsx +++ b/packages/server/src/verification/send-verification-email.tsx @@ -1,4 +1,7 @@ +import { renderAsync } from "@react-email/components"; +import VerifyEmailTemplate from "../emails/emails/verify-email"; import { sendEmailNotification } from "../utils/notifications/utils"; + export const sendEmail = async ({ email, subject, @@ -26,3 +29,25 @@ export const sendEmail = async ({ return true; }; + +export const sendVerificationEmail = async ({ + userName, + email, + verificationUrl, +}: { + userName: string; + email: string; + verificationUrl: string; +}) => { + const html = await renderAsync( + VerifyEmailTemplate({ + userName: userName || "User", + verificationUrl, + }), + ); + await sendEmail({ + email, + subject: "Verify your email", + text: html, + }); +};