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 */}
+
+
+
+
+ {/* 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,
+ });
+};