Merge pull request #4284 from Infisical/simplify-email-design

improvement(email-templates): simplify email design, refactor link/button to re-usable components and improve design
This commit is contained in:
Scott Wilson
2025-08-01 18:48:53 -07:00
committed by GitHub
28 changed files with 184 additions and 250 deletions

View File

@@ -1,7 +1,9 @@
import { Button, Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface AccessApprovalRequestTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
projectName: string;
@@ -38,18 +40,15 @@ export const AccessApprovalRequestTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
You have a new access approval request pending review for the project <strong>{projectName}</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]">
<strong>{requesterFullName}</strong> (
<Link href={`mailto:${requesterEmail}`} className="text-slate-700 no-underline">
{requesterEmail}
</Link>
) has requested {isTemporary ? "temporary" : "permanent"} access to <strong>{secretPath}</strong> in the{" "}
<strong>{requesterFullName}</strong> (<BaseLink href={`mailto:${requesterEmail}`}>{requesterEmail}</BaseLink>)
has requested {isTemporary ? "temporary" : "permanent"} access to <strong>{secretPath}</strong> in the{" "}
<strong>{environment}</strong> environment.
</Text>
{isTemporary && (
<Text className="text-[14px] text-red-500 leading-[24px]">
<Text className="text-[14px] text-red-600 leading-[24px]">
<strong>This access will expire {expiresIn} after approval.</strong>
</Text>
)}
@@ -67,13 +66,8 @@ export const AccessApprovalRequestTemplate = ({
</Text>
)}
</Section>
<Section className="text-center mt-[28px]">
<Button
href={approvalUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Review Request
</Button>
<Section className="text-center">
<BaseButton href={approvalUrl}>Review Request</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -0,0 +1,17 @@
import { Button } from "@react-email/components";
type Props = {
href: string;
children: string;
};
export const BaseButton = ({ href, children }: Props) => {
return (
<Button
href={href}
className="rounded-[8px] py-[12px] px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
{children}
</Button>
);
};

View File

@@ -16,23 +16,21 @@ export const BaseEmailWrapper = ({ title, preview, children, siteUrl }: BaseEmai
<Body className="bg-gray-300 my-auto mx-auto font-sans px-[8px] py-[4px]">
<Preview>{preview}</Preview>
<Container className="bg-white rounded-xl my-[40px] mx-auto pb-[0px] max-w-[500px]">
<Section className="border-0 border-b border-[#d1e309] border-solid bg-[#EBF852] mb-[44px] h-[10px] rounded-t-xl" />
<Section className="px-[32px] mb-[18px]">
<Section className="w-[48px] h-[48px] border border-solid border-gray-300 rounded-full bg-gray-100 mx-auto">
<Img
src={`https://infisical.com/_next/image?url=%2Fimages%2Flogo-black.png&w=64&q=75`}
width="32"
alt="Infisical Logo"
className="mx-auto"
/>
</Section>
<Section className="mb-[24px] px-[24px] mt-[24px]">
<Img
src="https://infisical.com/_next/image?url=%2Fimages%2Flogo-black.png&w=64&q=75"
width="36"
alt="Infisical Logo"
className="mx-auto"
/>
</Section>
<Hr className=" mb-[32px] mt-[0px] h-[1px]" />
<Section className="px-[28px]">{children}</Section>
<Hr className=" mt-[32px] mb-[0px] h-[1px]" />
<Section className="px-[24px] text-center">
<Text className="text-gray-500 text-[12px]">
Email sent via{" "}
<Link href={siteUrl} className="text-slate-700 no-underline">
<Link href={siteUrl} className="text-slate-700 underline decoration-slate-700">
Infisical
</Link>
</Text>

View File

@@ -0,0 +1,15 @@
import { Link } from "@react-email/components";
import React from "react";
type Props = {
href: string;
children: string;
};
export const BaseLink = ({ href, children }: Props) => {
return (
<Link href={href} className="text-slate-700 underline decoration-slate-700">
{children}
</Link>
);
};

View File

@@ -1,7 +1,8 @@
import { Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface EmailMfaTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
code: string;
@@ -25,11 +26,7 @@ export const EmailMfaTemplate = ({ code, siteUrl, isCloud }: EmailMfaTemplatePro
<strong>Not you?</strong>{" "}
{isCloud ? (
<>
Contact us at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>{" "}
immediately
Contact us at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink> immediately
</>
) : (
"Contact your administrator immediately"

View File

@@ -1,7 +1,8 @@
import { Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface EmailVerificationTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
code: string;
@@ -29,10 +30,7 @@ export const EmailVerificationTemplate = ({ code, siteUrl, isCloud }: EmailVerif
<strong>Questions about Infisical?</strong>{" "}
{isCloud ? (
<>
Email us at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
Email us at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink>
</>
) : (
"Contact your administrator"

View File

@@ -1,7 +1,8 @@
import { Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface ExternalImportFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
error: string;
@@ -21,12 +22,9 @@ export const ExternalImportFailedTemplate = ({ error, siteUrl, provider }: Exter
</Text>
<Text className="text-black text-[14px] leading-[24px]">
If your issue persists, you can contact the Infisical team at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
.
<BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink>.
</Text>
<Text className="text-[14px] text-red-500 leading-[24px]">
<Text className="text-[14px] text-red-600 leading-[24px]">
<strong>Error:</strong> "{error}"
</Text>
</Section>

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface IntegrationSyncFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -30,7 +31,7 @@ export const IntegrationSyncFailedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>{count}</strong> integration(s) failed to sync
</Heading>
<Section className="px-[24px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<strong>Project</strong>
<Text className="text-[14px] mt-[4px]">{projectName}</Text>
<strong>Environment</strong>
@@ -38,15 +39,10 @@ export const IntegrationSyncFailedTemplate = ({
<strong>Secret Path</strong>
<Text className="text-[14px] mt-[4px]">{secretPath}</Text>
<strong className="text-black">Failure Reason:</strong>
<Text className="text-[14px] mt-[4px] text-red-500 leading-[24px]">"{syncMessage}"</Text>
<Text className="text-[14px] mt-[4px] text-red-600 leading-[24px]">"{syncMessage}"</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={integrationUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View Integrations
</Button>
<Section className="text-center">
<BaseButton href={integrationUrl}>View Integrations</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,7 +1,8 @@
import { Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface NewDeviceLoginTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
email: string;
@@ -42,9 +43,7 @@ export const NewDeviceLoginTemplate = ({
<Text className="mb-[0px]">
If you believe that this login is suspicious, please contact{" "}
{isCloud ? (
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
<BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink>
) : (
"your administrator"
)}{" "}

View File

@@ -1,7 +1,8 @@
import { Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface OrgAdminBreakglassAccessTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
email: string;
@@ -35,10 +36,7 @@ export const OrgAdminBreakglassAccessTemplate = ({
<Text className="text-[14px] mt-[4px]">{userAgent}</Text>
<Text className="text-[14px]">
If you'd like to disable Admin SSO Bypass, please visit{" "}
<Link href={`${siteUrl}/organization/settings`} className="text-slate-700 no-underline">
Organization Security Settings
</Link>
.
<BaseLink href={`${siteUrl}/organization/settings`}>Organization Security Settings</BaseLink>.
</Text>
</Section>
</BaseEmailWrapper>

View File

@@ -2,6 +2,7 @@ import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface OrgAdminProjectGrantAccessTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview"> {
email: string;
@@ -24,8 +25,8 @@ export const OrgAdminProjectGrantAccessTemplate = ({
</Heading>
<Section className="px-[24px] mt-[36px] pt-[24px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px] mt-[4px]">
The organization admin <strong>{email}</strong> has self-issued direct access to the project{" "}
<strong>{projectName}</strong>.
The organization admin <BaseLink href={`mailto:${email}`}>{email}</BaseLink> has self-issued direct access to
the project <strong>{projectName}</strong>.
</Text>
</Section>
</BaseEmailWrapper>

View File

@@ -1,7 +1,9 @@
import { Button, Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface OrganizationInvitationTemplateProps extends Omit<BaseEmailWrapperProps, "preview" | "title"> {
metadata?: string;
@@ -36,15 +38,13 @@ export const OrganizationInvitationTemplate = ({
<br />
<strong>{organizationName}</strong> on <strong>Infisical</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]">
{inviterFirstName && inviterUsername ? (
<>
<strong>{inviterFirstName}</strong> (
<Link href={`mailto:${inviterUsername}`} className="text-slate-700 no-underline">
{inviterUsername}
</Link>
) has invited you to collaborate on <strong>{organizationName}</strong>.
<BaseLink href={`mailto:${inviterUsername}`}>{inviterUsername}</BaseLink>) has invited you to collaborate
on <strong>{organizationName}</strong>.
</>
) : (
<>
@@ -53,13 +53,12 @@ export const OrganizationInvitationTemplate = ({
)}
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
<Section className="text-center">
<BaseButton
href={`${callback_url}?token=${token}${metadata ? `&metadata=${metadata}` : ""}&to=${encodeURIComponent(email)}&organization_id=${organizationId}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Accept Invite
</Button>
</BaseButton>
</Section>
<Section className="mt-[24px] bg-gray-50 pt-[2px] pb-[16px] border border-solid border-gray-200 px-[24px] rounded-md text-gray-800">
<Text className="mb-[0px]">

View File

@@ -1,7 +1,9 @@
import { Button, Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface PasswordResetTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
email: string;
@@ -20,16 +22,13 @@ export const PasswordResetTemplate = ({ email, isCloud, siteUrl, callback_url, t
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>Account Recovery</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">A password reset was requested for your Infisical account.</Text>
<Text className="text-[14px]">
If you did not initiate this request, please contact{" "}
{isCloud ? (
<>
us immediately at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
us immediately at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink>
</>
) : (
"your administrator immediately"
@@ -37,13 +36,8 @@ export const PasswordResetTemplate = ({ email, isCloud, siteUrl, callback_url, t
.
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={`${callback_url}?token=${token}&to=${encodeURIComponent(email)}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Reset Password
</Button>
<Section className="text-center">
<BaseButton href={`${callback_url}?token=${token}&to=${encodeURIComponent(email)}`}>Reset Password</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,6 +1,8 @@
import { Button, Heading, Link, Section, Text } from "@react-email/components";
import { Button, Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseLink } from "@app/services/smtp/emails/BaseLink";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface PasswordSetupTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -16,19 +18,16 @@ export const PasswordSetupTemplate = ({ email, isCloud, siteUrl, callback_url, t
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>Password Setup</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">Someone requested to set up a password for your Infisical account.</Text>
<Text className="text-[14px] text-red-500">
<Text className="text-[14px] text-red-600">
Make sure you are already logged in to Infisical in the current browser before clicking the link below.
</Text>
<Text className="text-[14px]">
If you did not initiate this request, please contact{" "}
{isCloud ? (
<>
us immediately at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
us immediately at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink>
</>
) : (
"your administrator immediately"
@@ -36,7 +35,7 @@ export const PasswordSetupTemplate = ({ email, isCloud, siteUrl, callback_url, t
.
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Section className="text-center">
<Button
href={`${callback_url}?token=${token}&to=${encodeURIComponent(email)}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"

View File

@@ -1,7 +1,9 @@
import { Button, Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface ProjectAccessRequestTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
projectName: string;
@@ -30,26 +32,17 @@ export const ProjectAccessRequestTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
A user has requested access to the project <strong>{projectName}</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]">
<strong>{requesterName}</strong> (
<Link href={`mailto:${requesterEmail}`} className="text-slate-700 no-underline">
{requesterEmail}
</Link>
) has requested access to the project <strong>{projectName}</strong> in the organization{" "}
<strong>{orgName}</strong>.
<strong>{requesterName}</strong> (<BaseLink href={`mailto:${requesterEmail}`}>{requesterEmail}</BaseLink>) has
requested access to the project <strong>{projectName}</strong> in the organization <strong>{orgName}</strong>.
</Text>
<Text className="text-[14px] text-slate-700 leading-[24px]">
<strong className="text-black">User note:</strong> "{note}"
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={callback_url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Grant Access
</Button>
<Section className="text-center">
<BaseButton href={callback_url}>Grant Access</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface ProjectInvitationTemplateProps extends Omit<BaseEmailWrapperProps, "preview" | "title"> {
@@ -18,18 +19,13 @@ export const ProjectInvitationTemplate = ({ callback_url, workspaceName, siteUrl
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
You've been invited to join a project on Infisical
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]">
You've been invited to join the project <strong>{workspaceName}</strong>.
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={callback_url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Join Project
</Button>
<Section className="text-center">
<BaseButton href={callback_url}>Join Project</BaseButton>
</Section>
<Section className="mt-[24px] bg-gray-50 pt-[2px] pb-[16px] border border-solid border-gray-200 px-[24px] rounded-md text-gray-800">
<Text className="mb-[0px]">

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface ScimUserProvisionedTemplateProps extends Omit<BaseEmailWrapperProps, "preview" | "title"> {
@@ -24,18 +25,13 @@ export const ScimUserProvisionedTemplate = ({
<br />
<strong>{organizationName}</strong> on <strong>Infisical</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border text-center border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]">
You've been invited to collaborate on <strong>{organizationName}</strong>.
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={callback_url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Accept Invite
</Button>
<Section className="text-center">
<BaseButton href={callback_url}>Accept Invite</BaseButton>
</Section>
<Section className="mt-[24px] bg-gray-50 pt-[2px] pb-[16px] border border-solid border-gray-200 px-[24px] rounded-md text-gray-800">
<Text className="mb-[0px]">

View File

@@ -1,7 +1,9 @@
import { Button, Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface SecretApprovalRequestBypassedTemplateProps
extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -35,13 +37,10 @@ export const SecretApprovalRequestBypassedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
A secret approval request has been bypassed in the project <strong>{projectName}</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-black text-[14px] leading-[24px]">
<strong>{requesterFullName}</strong> (
<Link href={`mailto:${requesterEmail}`} className="text-slate-700 no-underline">
{requesterEmail}
</Link>
) has {requestType === "change" ? "merged" : "accessed"} a secret {requestType === "change" ? "to" : "in"}{" "}
<strong>{requesterFullName}</strong> (<BaseLink href={`mailto:${requesterEmail}`}>{requesterEmail}</BaseLink>)
has {requestType === "change" ? "merged" : "accessed"} a secret {requestType === "change" ? "to" : "in"}{" "}
<strong>{secretPath}</strong> in the <strong>{environment}</strong> environment without obtaining the required
approval.
</Text>
@@ -50,13 +49,8 @@ export const SecretApprovalRequestBypassedTemplate = ({
{bypassReason}"
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={approvalUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Review Bypass
</Button>
<Section className="text-center">
<BaseButton href={approvalUrl}>Review Bypass</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretApprovalRequestNeedsReviewTemplateProps
@@ -27,20 +28,15 @@ export const SecretApprovalRequestNeedsReviewTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
A secret approval request for the project <strong>{projectName}</strong> requires review
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">Hello {firstName},</Text>
<Text className="text-black text-[14px] leading-[24px]">
You have a new secret change request pending your review for the project <strong>{projectName}</strong> in the
organization <strong>{organizationName}</strong>.
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={approvalUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Review Changes
</Button>
<Section className="text-center">
<BaseButton href={approvalUrl}>Review Changes</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,7 +1,9 @@
import { Button, Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface SecretLeakIncidentTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
numberOfSecrets: number;
@@ -24,7 +26,7 @@ export const SecretLeakIncidentTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
Infisical has uncovered <strong>{numberOfSecrets}</strong> secret(s) from a recent commit
</Heading>
<Section className="px-[24px] mt-[36px] pt-[8px] pb-[8px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[8px] pb-[8px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">
You are receiving this notification because one or more leaked secrets have been detected in a recent commit
{(pusher_email || pusher_name) && (
@@ -33,11 +35,7 @@ export const SecretLeakIncidentTemplate = ({
pushed by <strong>{pusher_name ?? "Unknown Pusher"}</strong>{" "}
{pusher_email && (
<>
(
<Link href={`mailto:${pusher_email}`} className="text-slate-700 no-underline">
{pusher_email}
</Link>
)
(<BaseLink href={`mailto:${pusher_email}`}>{pusher_email}</BaseLink>)
</>
)}
</>
@@ -49,24 +47,16 @@ export const SecretLeakIncidentTemplate = ({
a comment in the given programming language. This will prevent future notifications from being sent out for
these secrets.
</Text>
<Text className="text-[14px] text-red-500">
<Text className="text-[14px] text-red-600">
If these are production secrets, please rotate them immediately.
</Text>
<Text className="text-[14px]">
Once you have taken action, be sure to update the status of the risk in the{" "}
<Link href={`${siteUrl}/organization/secret-scanning`} className="text-slate-700 no-underline">
Infisical Dashboard
</Link>
.
<BaseLink href={`${siteUrl}/organization/secret-scanning`}>Infisical Dashboard</BaseLink>.
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={`${siteUrl}/organization/secret-scanning`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View Leaked Secrets
</Button>
<Section className="text-center">
<BaseButton href={`${siteUrl}/organization/secret-scanning`}>View Leaked Secrets</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretRequestCompletedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -20,7 +21,7 @@ export const SecretRequestCompletedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>A secret has been shared with you</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] text-center pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] text-center pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">
{respondentUsername ? <strong>{respondentUsername}</strong> : "Someone"} shared a secret{" "}
{name && (
@@ -31,13 +32,8 @@ export const SecretRequestCompletedTemplate = ({
with you.
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={secretRequestUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View Secret
</Button>
<Section className="text-center">
<BaseButton href={secretRequestUrl}>View Secret</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretRotationFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -28,7 +29,7 @@ export const SecretRotationFailedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
Your <strong>{rotationType}</strong> rotation <strong>{rotationName}</strong> failed to rotate
</Heading>
<Section className="px-[24px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<strong>Name</strong>
<Text className="text-[14px] mt-[4px]">{rotationName}</Text>
<strong>Type</strong>
@@ -40,15 +41,12 @@ export const SecretRotationFailedTemplate = ({
<strong>Secret Path</strong>
<Text className="text-[14px] mt-[4px]">{secretPath}</Text>
<strong>Reason:</strong>
<Text className="text-[14px] text-red-500 mt-[4px]">{content}</Text>
<Text className="text-[14px] text-red-600 mt-[4px]">{content}</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={`${rotationUrl}?search=${rotationName}&secretPath=${secretPath}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
<Section className="text-center">
<BaseButton href={`${rotationUrl}?search=${rotationName}&secretPath=${secretPath}`}>
View in Infisical
</Button>
</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretScanningScanFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -30,7 +31,7 @@ export const SecretScanningScanFailedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
Infisical encountered an error while attempting to scan the resource <strong>{resourceName}</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<strong>Resource</strong>
<Text className="text-[14px] mt-[4px]">{resourceName}</Text>
<strong>Data Source</strong>
@@ -40,15 +41,10 @@ export const SecretScanningScanFailedTemplate = ({
<strong>Timestamp</strong>
<Text className="text-[14px] mt-[4px]">{timestamp}</Text>
<strong>Error</strong>
<Text className="text-[14px] text-red-500 mt-[4px]">{errorMessage}</Text>
<Text className="text-[14px] text-red-600 mt-[4px]">{errorMessage}</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View in Infisical
</Button>
<Section className="text-center">
<BaseButton href={url}>View in Infisical</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,7 +1,9 @@
import { Button, Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface SecretScanningSecretsDetectedTemplateProps
extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -32,7 +34,7 @@ export const SecretScanningSecretsDetectedTemplate = ({
Infisical has uncovered <strong>{numberOfSecrets}</strong> secret(s)
{isDiffScan ? " from a recent commit to" : " in"} <strong>{resourceName}</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[8px] pb-[8px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[8px] pb-[8px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">
You are receiving this notification because one or more leaked secrets have been detected
{isDiffScan && " in a recent commit"}
@@ -43,11 +45,7 @@ export const SecretScanningSecretsDetectedTemplate = ({
pushed by <strong>{authorName ?? "Unknown Pusher"}</strong>{" "}
{authorEmail && (
<>
(
<Link href={`mailto:${authorEmail}`} className="text-slate-700 no-underline">
{authorEmail}
</Link>
)
(<BaseLink href={`mailto:${authorEmail}`}>{authorEmail}</BaseLink>)
</>
)}
</>
@@ -65,24 +63,16 @@ export const SecretScanningSecretsDetectedTemplate = ({
a comment in the given programming language. This will prevent future notifications from being sent out for
these secrets.
</Text>
<Text className="text-[14px] text-red-500">
<Text className="text-[14px] text-red-600">
If these are production secrets, please rotate them immediately.
</Text>
<Text className="text-[14px]">
Once you have taken action, be sure to update the finding status in the{" "}
<Link href={url} className="text-slate-700 no-underline">
Infisical Dashboard
</Link>
.
<BaseLink href={url}>Infisical Dashboard</BaseLink>.
</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View Leaked Secrets
</Button>
<Section className="text-center">
<BaseButton href={url}>View Leaked Secrets</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface SecretSyncFailedTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -28,7 +29,7 @@ export const SecretSyncFailedTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
Your <strong>{syncDestination}</strong> sync <strong>{syncName}</strong> failed to complete
</Heading>
<Section className="px-[24px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[26px] pb-[4px] text-[14px] border border-solid border-gray-200 rounded-md bg-gray-50">
<strong>Name</strong>
<Text className="text-[14px] mt-[4px]">{syncName}</Text>
<strong>Destination</strong>
@@ -50,17 +51,12 @@ export const SecretSyncFailedTemplate = ({
{failureMessage && (
<>
<strong>Reason:</strong>
<Text className="text-[14px] text-red-500 mt-[4px]">{failureMessage}</Text>
<Text className="text-[14px] text-red-600 mt-[4px]">{failureMessage}</Text>
</>
)}
</Section>
<Section className="text-center mt-[28px]">
<Button
href={syncUrl}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
View in Infisical
</Button>
<Section className="text-center">
<BaseButton href={syncUrl}>View in Infisical</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface ServiceTokenExpiryNoticeTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -24,20 +25,15 @@ export const ServiceTokenExpiryNoticeTemplate = ({
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>Service token expiry notice</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">
Your service token <strong>{tokenName}</strong> for the project <strong>{projectName}</strong> will expire
within 24 hours.
</Text>
<Text>If this token is still needed for your workflow, please create a new one before it expires.</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={url}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Create New Token
</Button>
<Section className="text-center">
<BaseButton href={url}>Create New Token</BaseButton>
</Section>
</BaseEmailWrapper>
);

View File

@@ -1,7 +1,8 @@
import { Heading, Link, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
import { BaseLink } from "./BaseLink";
interface SignupEmailVerificationTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
code: string;
@@ -29,10 +30,7 @@ export const SignupEmailVerificationTemplate = ({ code, siteUrl, isCloud }: Sign
<strong>Questions about setting up Infisical?</strong>{" "}
{isCloud ? (
<>
Email us at{" "}
<Link href="mailto:support@infisical.com" className="text-slate-700 no-underline">
support@infisical.com
</Link>
Email us at <BaseLink href="mailto:support@infisical.com">support@infisical.com</BaseLink>
</>
) : (
"Contact your administrator"

View File

@@ -1,6 +1,7 @@
import { Button, Heading, Section, Text } from "@react-email/components";
import { Heading, Section, Text } from "@react-email/components";
import React from "react";
import { BaseButton } from "./BaseButton";
import { BaseEmailWrapper, BaseEmailWrapperProps } from "./BaseEmailWrapper";
interface UnlockAccountTemplateProps extends Omit<BaseEmailWrapperProps, "title" | "preview" | "children"> {
@@ -18,19 +19,14 @@ export const UnlockAccountTemplate = ({ token, siteUrl, callback_url }: UnlockAc
<Heading className="text-black text-[18px] leading-[28px] text-center font-normal p-0 mx-0">
<strong>Unlock your Infisical account</strong>
</Heading>
<Section className="px-[24px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Section className="px-[24px] mb-[28px] mt-[36px] pt-[12px] pb-[8px] border border-solid border-gray-200 rounded-md bg-gray-50">
<Text className="text-[14px]">
Your account has been temporarily locked due to multiple failed login attempts.
</Text>
<Text>If these attempts were not made by you, reset your password immediately.</Text>
</Section>
<Section className="text-center mt-[28px]">
<Button
href={`${callback_url}?token=${token}`}
className="rounded-md p-3 px-[28px] my-[8px] text-center text-[16px] bg-[#EBF852] border-solid border border-[#d1e309] text-black font-medium"
>
Unlock Account
</Button>
<Section className="text-center">
<BaseButton href={`${callback_url}?token=${token}`}>Unlock Account</BaseButton>
</Section>
</BaseEmailWrapper>
);