mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-15 20:25:23 +02:00
Merge pull request #4239 from Dokploy/feat/resend-verification-email-on-signin
feat: resend verification email on sign-in and improve template
This commit is contained in:
@@ -82,6 +82,16 @@ export default function Home({ IS_CLOUD }: Props) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
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);
|
toast.error(error.message);
|
||||||
setError(error.message || "An error occurred while logging in");
|
setError(error.message || "An error occurred while logging in");
|
||||||
return;
|
return;
|
||||||
|
|||||||
104
packages/server/src/emails/emails/verify-email.tsx
Normal file
104
packages/server/src/emails/emails/verify-email.tsx
Normal file
@@ -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 (
|
||||||
|
<Html>
|
||||||
|
<Head />
|
||||||
|
<Preview>{previewText}</Preview>
|
||||||
|
<Tailwind
|
||||||
|
config={{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
brand: "#007291",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Body className="bg-[#f4f4f5] my-auto mx-auto font-sans">
|
||||||
|
<Container className="my-[40px] mx-auto max-w-[520px]">
|
||||||
|
{/* Header */}
|
||||||
|
<Section className="bg-[#09090b] rounded-t-xl px-[40px] py-[32px] text-center">
|
||||||
|
<Img
|
||||||
|
src="https://raw.githubusercontent.com/Dokploy/website/refs/heads/main/apps/docs/public/logo-dokploy-blackpng.png"
|
||||||
|
width="190"
|
||||||
|
height="120"
|
||||||
|
alt="Dokploy"
|
||||||
|
className="my-0 mx-auto"
|
||||||
|
/>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Body */}
|
||||||
|
<Section className="bg-white px-[40px] py-[32px]">
|
||||||
|
<Heading className="text-[#09090b] text-[22px] font-semibold m-0 mb-[8px]">
|
||||||
|
Verify Your Email
|
||||||
|
</Heading>
|
||||||
|
<Text className="text-[#71717a] text-[14px] leading-[22px] m-0 mb-[24px]">
|
||||||
|
Hello {userName}, thank you for signing up for Dokploy. Please
|
||||||
|
verify your email address to activate your account.
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
{/* CTA Button */}
|
||||||
|
<Section className="text-center mb-[24px]">
|
||||||
|
<Button
|
||||||
|
href={verificationUrl}
|
||||||
|
className="bg-[#09090b] rounded-lg text-white text-[14px] font-semibold no-underline text-center px-[24px] py-[12px]"
|
||||||
|
>
|
||||||
|
Verify Email Address
|
||||||
|
</Button>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
<Text className="text-[#a1a1aa] text-[13px] leading-[20px] m-0 text-center mb-[16px]">
|
||||||
|
If the button above doesn't work, copy and paste the following
|
||||||
|
link into your browser:
|
||||||
|
</Text>
|
||||||
|
<Text className="text-[#71717a] text-[12px] leading-[18px] m-0 text-center break-all">
|
||||||
|
{verificationUrl}
|
||||||
|
</Text>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<Section className="bg-[#fafafa] rounded-b-xl px-[40px] py-[24px] text-center border-t border-solid border-[#e4e4e7]">
|
||||||
|
<Text className="text-[#a1a1aa] text-[12px] leading-[18px] m-0">
|
||||||
|
This is an automated email from{" "}
|
||||||
|
<Link
|
||||||
|
href="https://dokploy.com"
|
||||||
|
className="text-[#71717a] underline"
|
||||||
|
>
|
||||||
|
Dokploy Cloud
|
||||||
|
</Link>
|
||||||
|
. If you didn't create an account, you can safely ignore this
|
||||||
|
email.
|
||||||
|
</Text>
|
||||||
|
</Section>
|
||||||
|
</Container>
|
||||||
|
</Body>
|
||||||
|
</Tailwind>
|
||||||
|
</Html>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VerifyEmailTemplate;
|
||||||
@@ -21,7 +21,10 @@ import {
|
|||||||
updateWebServerSettings,
|
updateWebServerSettings,
|
||||||
} from "../services/web-server-settings";
|
} from "../services/web-server-settings";
|
||||||
import { getHubSpotUTK, submitToHubSpot } from "../utils/tracking/hubspot";
|
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 { getPublicIpWithFallback } from "../wss/utils";
|
||||||
import { ac, adminRole, memberRole, ownerRole } from "./access-control";
|
import { ac, adminRole, memberRole, ownerRole } from "./access-control";
|
||||||
|
|
||||||
@@ -106,14 +109,13 @@ const { handler, api } = betterAuth({
|
|||||||
emailVerification: {
|
emailVerification: {
|
||||||
sendOnSignUp: true,
|
sendOnSignUp: true,
|
||||||
autoSignInAfterVerification: true,
|
autoSignInAfterVerification: true,
|
||||||
|
sendOnSignIn: true,
|
||||||
sendVerificationEmail: async ({ user, url }) => {
|
sendVerificationEmail: async ({ user, url }) => {
|
||||||
if (IS_CLOUD) {
|
if (IS_CLOUD) {
|
||||||
await sendEmail({
|
await sendVerificationEmail({
|
||||||
|
userName: user.name || "User",
|
||||||
email: user.email,
|
email: user.email,
|
||||||
subject: "Verify your email",
|
verificationUrl: url,
|
||||||
text: `
|
|
||||||
<p>Click the link to verify your email: <a href="${url}">Verify Email</a></p>
|
|
||||||
`,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import { renderAsync } from "@react-email/components";
|
||||||
|
import VerifyEmailTemplate from "../emails/emails/verify-email";
|
||||||
import { sendEmailNotification } from "../utils/notifications/utils";
|
import { sendEmailNotification } from "../utils/notifications/utils";
|
||||||
|
|
||||||
export const sendEmail = async ({
|
export const sendEmail = async ({
|
||||||
email,
|
email,
|
||||||
subject,
|
subject,
|
||||||
@@ -26,3 +29,25 @@ export const sendEmail = async ({
|
|||||||
|
|
||||||
return true;
|
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,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user