Skip to content

Commit

Permalink
feature: Add email templates for better email sending. (🚀 Feature: Ad…
Browse files Browse the repository at this point in the history
…d email template for better email experience . code100x#584)
  • Loading branch information
jagadeeshm2002 authored Nov 12, 2024
1 parent 2ed4b46 commit 8ac8a3b
Show file tree
Hide file tree
Showing 22 changed files with 1,048 additions and 0 deletions.
43 changes: 43 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#
# Database
#
DATABASE_URL="postgres://postgres:9876@localhost:5432/postgres"
#
# AUTH
#
NEXTAUTH_SECRET="koXrQGB5TFD4KALDX4kAvnQ5RHHvAOIzB"
NEXTAUTH_URL="http://localhost:3000"

NEXT_PUBLIC_BASE_URL="http://localhost:3000"

#
# Bunny CDN
#
CDN_API_KEY="api-key"
CDN_BASE_UPLOAD_URL="https://sg.storage.bunnycdn.com/job-board/assets"
CDN_BASE_ACCESS_URL="https://job-board.b-cdn.net/assets"

NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=maps-api-key

#
# Email SMTP credentials
#
EMAIL_USER="[email protected]"
EMAIL_PASSWORD="syhc qfxx ikcd daeq"
EMAIL_USERNAME="jagadeesh"
EMAIL_SERVICE=gmail
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587

#
# Google OAuth credentials
#
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

# go to https://lightcast.io/open-skills and signup to recieve your credentials
LIGHTCAST_CLIENT_ID=
LIGHTCAST_CLIENT_SECRET=

# To run the application in production environment / check the envs
# SKIP_ENV_CHECK=true npm run [replace with your script name]
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=maps-api-key
#
EMAIL_USER= # your email ex: [email protected]
EMAIL_PASSWORD=
EMAIL_USERNAME="JOB BOARD"
EMAIL_SERVICE=gmail
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
Expand Down
186 changes: 186 additions & 0 deletions src/components/email/BaseEmailHtml.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/* eslint-disable @next/next/no-head-element */
import BaseTable from './BaseTable';
import EmailBodyLogo from './EmailBodyLogo';
import EmailHead from './EmailHead';

import RawHtml from './RawHtml';
import Row from './Row';

const Html = (props: { children: React.ReactNode }) => (
<>
<RawHtml html="<!doctype html>" />
<html>{props.children}</html>
</>
);

export const BaseEmailHtml = (props: {
children: React.ReactNode;
subject: string;
}) => {
return (
<Html>
<EmailHead title={props.subject} />
<body style={{ wordSpacing: 'normal', backgroundColor: '#F3F4F6' }}>
<div style={{ backgroundColor: '#F3F4F6' }}>
<RawHtml
html={`<!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->`}
/>

{/* Header with logo and platform name */}
<div
style={{
margin: '0px auto',
maxWidth: 600,
textAlign: 'center',
padding: '20px 0',
}}
>
<EmailBodyLogo />
</div>

{/* Main Content */}
<div
style={{
margin: '0px auto',
maxWidth: 600,
borderRadius: '8px',
border: '1px solid #E5E7EB',
padding: '2px',
backgroundColor: '#FFFFFF',
}}
>
<RawHtml
html={`<!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" className="" style="width:600px;" width="600" bgcolor="#FFFFFF" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->`}
/>
<div
style={{
background: '#FFFFFF',
backgroundColor: '#FFFFFF',
margin: '0px auto',
maxWidth: 600,
}}
>
<Row
align="center"
border={0}
style={{
background: '#FFFFFF',
backgroundColor: '#FFFFFF',
width: '100%',
}}
>
<td
style={{
direction: 'ltr',
fontSize: 0,
padding: 0,
textAlign: 'center',
}}
>
<RawHtml
html={`<!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td className="" style="vertical-align:top;width:598px;" ><![endif]-->`}
/>
<div
className="mj-column-per-100 mj-outlook-group-fix"
style={{
fontSize: 0,
textAlign: 'left',
direction: 'ltr',
display: 'inline-block',
verticalAlign: 'top',
width: '100%',
}}
>
<Row
border={0}
style={{ verticalAlign: 'top' }}
width="100%"
>
<td
align="center"
style={{
fontSize: 0,
padding: '10px 25px',
wordBreak: 'break-word',
}}
>
<div
style={{
fontFamily: 'Helvetica, Arial, sans-serif',
fontSize: 16,
fontWeight: 500,
lineHeight: 1.5,
textAlign: 'center',
color: '#101010',
backgroundColor: '#FFFFFF',
}}
>
{props.children}
</div>
</td>
</Row>
</div>
<RawHtml html="<!--[if mso | IE]></td></tr></table><![endif]-->" />
</td>
</Row>
</div>
</div>
{/* Footer with logo, address, social links, and privacy policy */}
<div
style={{
margin: '0px auto',
maxWidth: 600,
textAlign: 'center',
padding: '20px 0',
color: '#6B7280',
fontFamily: 'Helvetica, Arial, sans-serif',
}}
>
<EmailBodyLogo />
<BaseTable>
<p>1234 Example Street, Suite 100, City, State, Zip</p>
<div
style={{
display: 'flex',
justifyContent: 'center',
gap: '10px',
marginTop: '10px',
}}
>
<a
href="https://facebook.com"
style={{ color: '#6B7280', textDecoration: 'none' }}
>
Facebook
</a>
<a
href="https://twitter.com"
style={{ color: '#6B7280', textDecoration: 'none' }}
>
Twitter
</a>
<a
href="https://instagram.com"
style={{ color: '#6B7280', textDecoration: 'none' }}
>
Instagram
</a>
</div>
<p style={{ marginTop: '10px' }}>
<a
href="/privacy-policy"
style={{ color: '#6B7280', textDecoration: 'underline' }}
>
Privacy Policy
</a>
</p>
</BaseTable>
</div>

<RawHtml html="<!--[if mso | IE]></td></tr></table><![endif]-->" />
</div>
</body>
</Html>
);
};
29 changes: 29 additions & 0 deletions src/components/email/BaseTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
interface BaseTableProps extends Omit<React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "border"> {
align?: React.TableHTMLAttributes<HTMLTableElement>["align"];
border?: React.TableHTMLAttributes<HTMLTableElement>["border"];
}

const BaseTable: React.FC<BaseTableProps> = ({ children, align, border, ...props }) => (
<table
align={align || "center"}
cellSpacing="0"
border={border||0}
style={{
borderCollapse: "collapse",
borderSpacing: "0",
boxSizing: "border-box",
fontFamily: "helvetica, arial, sans-serif !important",
margin: "0",
padding: "0",
position: "relative",
textAlign: "left",
verticalAlign: "top",
width: "100%",
}}
{...props}
>
{children}
</table>
);

export default BaseTable;
51 changes: 51 additions & 0 deletions src/components/email/CallToAction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from "react";

type Props = {
buttonText?: string;
buttonLink?: string;
};

export function CallToAction({
buttonText = "Call to Action",
buttonLink = "#",
}: Props) {
return (
<table
role="presentation"
border={0}
cellPadding="0"
cellSpacing="0"
style={{
margin: "20px auto",
textAlign: "center",
width: "100%",
}}
>
<tbody>
<tr>
<td align="center">
<a
href={buttonLink}
style={{
backgroundColor: "#0073e6",
color: "#ffffff",
fontFamily: "Helvetica, Arial, sans-serif",
fontSize: "16px",
fontWeight: "bold",
lineHeight: "1.5",
padding: "12px 24px",
textDecoration: "none",
borderRadius: "5px",
display: "inline-block",
width: "100%",
maxWidth: "200px",
}}
>
{buttonText}
</a>
</td>
</tr>
</tbody>
</table>
);
}
Loading

1 comment on commit 8ac8a3b

@Kevinkp09
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have pushed your env file also. Please remove that.

Please sign in to comment.