-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: 7HR4IZ3 <[email protected]>
- Loading branch information
Showing
17 changed files
with
803 additions
and
619 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from "./templates" | ||
export * from "./sender" | ||
export * from "./utils" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import nodemailer from "nodemailer" | ||
import config from "../utils/config" | ||
import sql from "../utils/db" | ||
|
||
export interface MailOptions { | ||
subject: string | ||
to: string | ||
from: string | ||
text: string | ||
} | ||
|
||
const transporter = nodemailer.createTransport({ | ||
host: config.SMTP_HOST, | ||
port: config.SMTP_PORT, | ||
secure: true, | ||
auth: { | ||
user: config.SMTP_USER, | ||
pass: config.SMTP_PASSWORD, | ||
}, | ||
}) | ||
|
||
export async function sendEmail(body: MailOptions) { | ||
if ( | ||
!config.SMTP_HOST || | ||
!config.SMTP_PORT || | ||
!config.SMTP_USER || | ||
!config.SMTP_PASSWORD | ||
) { | ||
return console.warn( | ||
"[EMAIL] SMTP environment variables are not set. Skipping email sending.", | ||
) | ||
} | ||
|
||
// TODO: extract to another function | ||
const blockList = await sql`select email from _email_block_list` | ||
const blockedEmails = blockList.map(({ email }) => email) | ||
|
||
if (blockedEmails.includes(body.to)) { | ||
return console.warn("[EMAIL] Email in the block list, skipping sending.") | ||
} | ||
|
||
// TODO: should probably have an temp email server that checks if test account receives the mails | ||
if (body.to === "[email protected]") { | ||
return console.warn("[EMAIL] Not sending email to test account") | ||
} | ||
|
||
await transporter.sendMail(body) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,43 @@ | ||
import { signJWT } from "@/src/api/v1/auth/utils" | ||
import { sendEmail } from "./sendEmail" | ||
import { MailOptions } from "." | ||
import config from "../utils/config" | ||
import { extractFirstName } from "./utils" | ||
|
||
function sanitizeName(name: string): string { | ||
return name.replace(/\s+/g, " ").trim() | ||
} | ||
|
||
function extractFirstName(name: string): string { | ||
if (!name) return "there" | ||
const sanitizedName = sanitizeName(name) | ||
return sanitizedName.split(" ")[0] | ||
} | ||
|
||
export async function sendVerifyEmail(email: string, name: string = "") { | ||
const token = await signJWT({ email }) | ||
|
||
const confirmLink = `${process.env.API_URL}/v1/users/verify-email?token=${token}` | ||
|
||
await sendEmail(CONFIRM_EMAIL(email, name, confirmLink)) | ||
} | ||
|
||
export function INVITE_EMAIL(email: string, orgName: string, link: string) { | ||
export function INVITE_EMAIL( | ||
email: string, | ||
orgName: string, | ||
inviteLink: string, | ||
): MailOptions { | ||
return { | ||
subject: `You've been invited to Lunary`, | ||
to: [email], | ||
reply_to: "[email protected]", | ||
from: process.env.GENERIC_SENDER, | ||
subject: "You've been invited to Lunary", | ||
to: email, | ||
from: config.GENERIC_SENDER_ADDRESS!, | ||
text: `Hi, | ||
You've been invited to join ${orgName} on Lunary. | ||
Please click on the following link to accept the invitation: | ||
${link} | ||
${inviteLink} | ||
We're looking forward to having you on board! | ||
You can reply to this email if you have any question. | ||
Thanks | ||
- The Lunary team`, | ||
- The Lunary team | ||
`, | ||
} | ||
} | ||
|
||
export function CONFIRM_EMAIL( | ||
email: string, | ||
name: string, | ||
confirmLink: string, | ||
) { | ||
): MailOptions { | ||
return { | ||
subject: `confirm your email`, | ||
to: [email], | ||
reply_to: "[email protected]", | ||
from: process.env.GENERIC_SENDER, | ||
subject: `Confirm your email`, | ||
to: email, | ||
from: config.GENERIC_SENDER_ADDRESS!, | ||
|
||
text: `Hi ${extractFirstName(name)}, | ||
|
@@ -68,12 +54,14 @@ Thanks | |
} | ||
} | ||
|
||
export function RESET_PASSWORD(email: string, confirmLink: string) { | ||
export function RESET_PASSWORD( | ||
email: string, | ||
confirmLink: string, | ||
): MailOptions { | ||
return { | ||
subject: `Reset your password`, | ||
to: [email], | ||
reply_to: "[email protected]", | ||
from: process.env.GENERIC_SENDER, | ||
to: email, | ||
from: config.GENERIC_SENDER_ADDRESS!, | ||
text: `Hi, | ||
Please click on the link below to reset your password: | ||
|
@@ -86,12 +74,15 @@ You can reply to this email if you have any question. | |
} | ||
} | ||
|
||
export function WELCOME_EMAIL(email: string, name: string, projectId: string) { | ||
export function WELCOME_EMAIL( | ||
email: string, | ||
name: string, | ||
projectId: string, | ||
): MailOptions { | ||
return { | ||
subject: `welcome to Lunary`, | ||
to: [email], | ||
reply_to: "[email protected]", | ||
from: process.env.PERSONAL_SENDER || process.env.GENERIC_SENDER, | ||
subject: `Welcome to Lunary`, | ||
to: email, | ||
from: config.PERSONAL_SENDER_ADDRESS || config.GENERIC_SENDER_ADDRESS!, | ||
text: `Hi ${extractFirstName(name)}, | ||
I'm Vince, co-founder of lunary. | ||
|
@@ -111,12 +102,15 @@ Vince`, | |
} | ||
} | ||
|
||
export function UPGRADE_EMAIL(email: string, name: string, plan: string) { | ||
export function UPGRADE_EMAIL( | ||
email: string, | ||
name: string, | ||
plan: string, | ||
): MailOptions { | ||
return { | ||
subject: `Your account has been upgraded`, | ||
to: [email], | ||
reply_to: "[email protected]", | ||
from: process.env.GENERIC_SENDER, | ||
to: email, | ||
from: config.GENERIC_SENDER_ADDRESS!, | ||
text: `Hi ${extractFirstName(name)}, | ||
Your account has been upgraded to the ${plan} plan. | ||
|
@@ -125,16 +119,15 @@ The extra features and higher limits are now available to you. | |
Reply to this email if you have any question. | ||
- The Lunary Team`, | ||
- The Lunary team`, | ||
} | ||
} | ||
|
||
export function CANCELED_EMAIL(email: string, name: string) { | ||
export function CANCELED_EMAIL(email: string, name: string): MailOptions { | ||
return { | ||
subject: `Important: subscription canceled`, | ||
to: [email], | ||
from: process.env.GENERIC_SENDER, | ||
reply_to: "[email protected]", | ||
to: email, | ||
from: config.GENERIC_SENDER_ADDRESS!, | ||
text: `Hi ${extractFirstName(name)}, | ||
You have canceled your subscription. We're sad to see you go :( | ||
|
@@ -143,22 +136,21 @@ At the end of your billing period, your account will be downgraded to the free p | |
*Important: any data older than 30 days (free plan limits) will be permanently deleted.* | ||
If this was a mistake, you can upgrade again at any time here: https://app.lunary.ai/billing | ||
If this was a mistake, you can upgrade again at any time here: ${process.env.APP_URL}/billing | ||
Would you mind telling us why you canceled? We're always looking to improve. | ||
Thank you for trying Lunary. | ||
Vince & Hugh - founders of Lunary`, | ||
- The Lunary team`, | ||
} | ||
} | ||
|
||
export function FULLY_CANCELED_EMAIL(email: string, name: string) { | ||
export function FULLY_CANCELED_EMAIL(email: string, name: string): MailOptions { | ||
return { | ||
subject: `Sorry to see you go..`, | ||
reply_to: "[email protected]", | ||
to: [email], | ||
from: process.env.GENERIC_SENDER, | ||
subject: `Sorry to see you go...`, | ||
to: email, | ||
from: config.GENERIC_SENDER_ADDRESS!, | ||
text: `Hi ${extractFirstName(name)}, | ||
Your account has been downgraded to the free plan. | ||
|
@@ -173,27 +165,26 @@ If you can take 30 seconds to reply to this email with one of the following reas | |
4. It's too expensive | ||
5. Other: ____________ | ||
If this was a mistake, you can upgrade again at any time here: https://app.lunary.ai/billing | ||
If this was a mistake, you can upgrade again at any time here: ${process.env.APP_URL}/billing | ||
Thank you for trying Lunary. | ||
Vince & Hugh - founders of Lunary`, | ||
- The Lunary team`, | ||
} | ||
} | ||
|
||
export function LIMITED_EMAIL(email: string, name: string) { | ||
export function LIMITED_EMAIL(email: string, name: string): MailOptions { | ||
return { | ||
subject: `Action Required: Events limit reached`, | ||
to: [email], | ||
reply_to: "[email protected]", | ||
from: process.env.GENERIC_SENDER, | ||
to: email, | ||
from: config.GENERIC_SENDER_ADDRESS!, | ||
text: `Hi ${extractFirstName(name)}, | ||
Congratulations! You've reached your free ingested event limit for the month, which means you're making great use of Lunary. | ||
As a result, your account has been temporarily limited (don't worry, your data is safe and sound). | ||
To continue enjoying our services without interruption, please consider upgrading your account here: https://app.lunary.ai/billing | ||
To continue enjoying our services without interruption, please consider upgrading your account here: ${process.env.APP_URL}/billing | ||
If you have any questions, feel free to reply to this email. | ||
|
Oops, something went wrong.