mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 02:10:12 -06:00
feat: throw explicit error if smtp is not configured (#1784)
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
committed by
GitHub
parent
17410ba14c
commit
ddc06b19bf
@@ -28,8 +28,10 @@ const MembersLoading = () => (
|
||||
</div>
|
||||
|
||||
<div className="p-4">
|
||||
{[1, 2, 3].map((_) => (
|
||||
<div className="grid-cols-20 grid h-12 content-center rounded-t-lg bg-white p-4 text-left text-sm font-semibold text-slate-900">
|
||||
{[1, 2, 3].map((i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="grid-cols-20 grid h-12 content-center rounded-t-lg bg-white p-4 text-left text-sm font-semibold text-slate-900">
|
||||
<Skeleton className="col-span-2 h-10 w-10 rounded-full" />
|
||||
<Skeleton className="col-span-5 h-8 w-24" />
|
||||
<Skeleton className="col-span-5 h-8 w-24" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { sendInviteAcceptedEmail } from "@/app/lib/email";
|
||||
import { getServerSession } from "next-auth";
|
||||
|
||||
import { authOptions } from "@formbricks/lib/authOptions";
|
||||
import { sendInviteAcceptedEmail } from "@formbricks/lib/emails/emails";
|
||||
import { env } from "@formbricks/lib/env.mjs";
|
||||
import { deleteInvite, getInvite } from "@formbricks/lib/invite/service";
|
||||
import { verifyInviteToken } from "@formbricks/lib/jwt";
|
||||
@@ -38,7 +38,7 @@ export default async function JoinTeam({ searchParams }) {
|
||||
await createMembership(invite.teamId, currentUser.user.id, { accepted: true, role: invite.role });
|
||||
await deleteInvite(inviteId);
|
||||
|
||||
sendInviteAcceptedEmail(invite.creator.name ?? "", currentUser.user?.name, invite.creator.email);
|
||||
sendInviteAcceptedEmail(invite.creator.name ?? "", currentUser.user?.name ?? "", invite.creator.email);
|
||||
|
||||
return <RightAccountContent />;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { sendEmail } from "@/app/lib/email";
|
||||
import { withEmailTemplate } from "@/app/lib/email-template";
|
||||
|
||||
import { WEBAPP_URL } from "@formbricks/lib/constants";
|
||||
import { withEmailTemplate } from "@formbricks/lib/emails/email-template";
|
||||
import { sendEmail } from "@formbricks/lib/emails/emails";
|
||||
|
||||
import { Insights, NotificationResponse, Survey, SurveyResponse } from "./types";
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { responses } from "@/app/lib/api/response";
|
||||
import { transformErrorToDetails } from "@/app/lib/api/validator";
|
||||
import { sendResponseFinishedEmail } from "@/app/lib/email";
|
||||
import { headers } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { INTERNAL_SECRET } from "@formbricks/lib/constants";
|
||||
import { sendResponseFinishedEmail } from "@formbricks/lib/emails/emails";
|
||||
import { getIntegrations } from "@formbricks/lib/integration/service";
|
||||
import { getSurvey, updateSurvey } from "@formbricks/lib/survey/service";
|
||||
import { convertDatesInObject } from "@formbricks/lib/time";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { sendForgotPasswordEmail } from "@/app/lib/email";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { sendForgotPasswordEmail } from "@formbricks/lib/emails/emails";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const { email } = await request.json();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { sendPasswordResetNotifyEmail } from "@/app/lib/email";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { sendPasswordResetNotifyEmail } from "@formbricks/lib/emails/emails";
|
||||
import { verifyToken } from "@formbricks/lib/jwt";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { sendInviteAcceptedEmail, sendVerificationEmail } from "@/app/lib/email";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { EMAIL_VERIFICATION_DISABLED, INVITE_DISABLED, SIGNUP_ENABLED } from "@formbricks/lib/constants";
|
||||
import { sendInviteAcceptedEmail, sendVerificationEmail } from "@formbricks/lib/emails/emails";
|
||||
import { env } from "@formbricks/lib/env.mjs";
|
||||
import { deleteInvite } from "@formbricks/lib/invite/service";
|
||||
import { verifyInviteToken } from "@formbricks/lib/jwt";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { sendVerificationEmail } from "@/app/lib/email";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { sendVerificationEmail } from "@formbricks/lib/emails/emails";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const { email } = await request.json();
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
export const withEmailTemplate = (content: string) =>
|
||||
`<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1"
|
||||
/>
|
||||
<base target="_blank" />
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #f1f5f9;
|
||||
font-family: "Poppins", "Helvetica Neue", "Segoe UI", Helvetica,
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
line-height: 26px;
|
||||
margin: 0;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #f4f4f4;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 1px dashed #94a3b8;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
table td {
|
||||
padding: 5px;
|
||||
}
|
||||
.socialicons {
|
||||
max-width: 200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 27px;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
background-color: #f8fafc;
|
||||
padding: 30px;
|
||||
max-width: 525px;
|
||||
margin: 0 auto;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.brandcolor {
|
||||
color: #00c4b8;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
background-color: #f1f5f9;
|
||||
padding: 1rem;
|
||||
border-radius: 1rem;
|
||||
color: #475569;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.tooltip a {
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-top:12px;
|
||||
background: #0f172a;
|
||||
border-radius: 8px;
|
||||
text-decoration: none !important;
|
||||
color: #fff !important;
|
||||
font-weight: 500;
|
||||
padding: 10px 30px;
|
||||
display: inline-block;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.button:hover {
|
||||
background: #334155;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #cbd5e1;
|
||||
}
|
||||
.footer a {
|
||||
color: #cbd5e1;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.gutter {
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.gutter img {
|
||||
max-width: 280px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #00c4b8;
|
||||
}
|
||||
a:hover {
|
||||
color: #00e6ca;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
font-weight: 600;
|
||||
}
|
||||
@media screen and (max-width: 600px) {
|
||||
.wrap {
|
||||
max-width: auto;
|
||||
}
|
||||
.gutter {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body
|
||||
style="
|
||||
background-color: #f1f5f9;
|
||||
font-family: 'Poppins', 'Helvetica Neue', 'Segoe UI', Helvetica,
|
||||
sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 26px;
|
||||
margin: 0;
|
||||
color: #1e293b;
|
||||
"
|
||||
>
|
||||
<div class="gutter" style="padding: 30px">
|
||||
<a href="https://formbricks.com" target="_blank">
|
||||
<img
|
||||
src="https://s3.eu-central-1.amazonaws.com/listmonk-formbricks/Formbricks-Light-transparent.png"
|
||||
alt="Formbricks Logo"
|
||||
/></a>
|
||||
</div>
|
||||
<div
|
||||
class="wrap"
|
||||
style="
|
||||
background-color: #f8fafc;
|
||||
padding: 30px;
|
||||
max-width: 525px;
|
||||
margin: 0 auto;
|
||||
border-radius: 12px;
|
||||
"
|
||||
>
|
||||
${content}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="footer"
|
||||
style="text-align: center; font-size: 12px; color: #cbd5e1"
|
||||
>
|
||||
<table class="socialicons">
|
||||
<tr>
|
||||
<td>
|
||||
<a target="_blank" href="https://twitter.com/formbricks"
|
||||
><img
|
||||
title="Twitter"
|
||||
src="https://s3.eu-central-1.amazonaws.com/listmonk-formbricks/Twitter-transp.png"
|
||||
alt="Tw"
|
||||
width="32"
|
||||
/></a>
|
||||
</td>
|
||||
<td>
|
||||
<a target="_blank" href="https://formbricks.com/github"
|
||||
><img
|
||||
title="GitHub"
|
||||
src="https://s3.eu-central-1.amazonaws.com/listmonk-formbricks/Github-transp.png"
|
||||
alt="GitHub"
|
||||
width="32"
|
||||
/></a>
|
||||
</td>
|
||||
<td>
|
||||
<a target="_blank" href="https://formbricks.com/discord"
|
||||
><img
|
||||
title="Discord"
|
||||
src="https://s3.eu-central-1.amazonaws.com/listmonk-formbricks/Discord-transp.png"
|
||||
alt="Discord"
|
||||
width="32"
|
||||
/></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p style="padding-top: 8px; line-height: initial">
|
||||
Formbricks ${new Date().getFullYear()}. All rights reserved.<br />
|
||||
<a
|
||||
style="text-decoration: none"
|
||||
href="https://formbricks.com/imprint"
|
||||
target="_blank"
|
||||
>Imprint</a
|
||||
>
|
||||
|
|
||||
<a
|
||||
style="text-decoration: none"
|
||||
href="https://formbricks.com/privacy-policy"
|
||||
target="_blank"
|
||||
>Privacy Policy</a
|
||||
>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
@@ -1,192 +0,0 @@
|
||||
import { getQuestionResponseMapping } from "@/app/lib/responses/questionResponseMapping";
|
||||
|
||||
import {
|
||||
MAIL_FROM,
|
||||
SMTP_HOST,
|
||||
SMTP_PASSWORD,
|
||||
SMTP_PORT,
|
||||
SMTP_SECURE_ENABLED,
|
||||
SMTP_USER,
|
||||
WEBAPP_URL,
|
||||
} from "@formbricks/lib/constants";
|
||||
import { createInviteToken, createToken, createTokenForLinkSurvey } from "@formbricks/lib/jwt";
|
||||
import { TResponse } from "@formbricks/types/responses";
|
||||
import { TSurveyQuestion } from "@formbricks/types/surveys";
|
||||
|
||||
import { withEmailTemplate } from "./email-template";
|
||||
|
||||
const nodemailer = require("nodemailer");
|
||||
|
||||
interface sendEmailData {
|
||||
to: string;
|
||||
replyTo?: string;
|
||||
subject: string;
|
||||
text?: string;
|
||||
html: string;
|
||||
}
|
||||
|
||||
export const sendEmail = async (emailData: sendEmailData) => {
|
||||
let transporter = nodemailer.createTransport({
|
||||
host: SMTP_HOST,
|
||||
port: SMTP_PORT,
|
||||
secure: SMTP_SECURE_ENABLED, // true for 465, false for other ports
|
||||
auth: {
|
||||
user: SMTP_USER,
|
||||
pass: SMTP_PASSWORD,
|
||||
},
|
||||
// logger: true,
|
||||
// debug: true,
|
||||
});
|
||||
const emailDefaults = {
|
||||
from: `Formbricks <${MAIL_FROM || "noreply@formbricks.com"}>`,
|
||||
};
|
||||
await transporter.sendMail({ ...emailDefaults, ...emailData });
|
||||
};
|
||||
|
||||
export const sendVerificationEmail = async (user) => {
|
||||
const token = createToken(user.id, user.email, {
|
||||
expiresIn: "1d",
|
||||
});
|
||||
const verifyLink = `${WEBAPP_URL}/auth/verify?token=${encodeURIComponent(token)}`;
|
||||
const verificationRequestLink = `${WEBAPP_URL}/auth/verification-requested?email=${encodeURIComponent(
|
||||
user.email
|
||||
)}`;
|
||||
await sendEmail({
|
||||
to: user.email,
|
||||
subject: "Welcome to Formbricks 🤍",
|
||||
html: withEmailTemplate(`<h1>Welcome!</h1>
|
||||
To start using Formbricks please verify your email by clicking the button below:<br/><br/>
|
||||
<a class="button" href="${verifyLink}">Confirm email</a><br/>
|
||||
<br/>
|
||||
<strong>The link is valid for 24h.</strong><br/><br/>If it has expired please request a new token here:
|
||||
<a href="${verificationRequestLink}">Request new verification</a><br/>
|
||||
<br/>
|
||||
Your Formbricks Team`),
|
||||
});
|
||||
};
|
||||
|
||||
export const sendLinkSurveyToVerifiedEmail = async (data) => {
|
||||
const surveyId = data.surveyId;
|
||||
const email = data.email;
|
||||
const surveyData = data.surveyData;
|
||||
const token = createTokenForLinkSurvey(surveyId, email);
|
||||
const surveyLink = `${WEBAPP_URL}/s/${surveyId}?verify=${encodeURIComponent(token)}`;
|
||||
await sendEmail({
|
||||
to: data.email,
|
||||
subject: "Your Formbricks Survey",
|
||||
html: withEmailTemplate(`<h1>Hey 👋</h1>
|
||||
Thanks for validating your email. Here is your Survey.<br/><br/>
|
||||
<strong>${surveyData.name}</strong>
|
||||
<p>${surveyData.subheading}</p>
|
||||
<a class="button" href="${surveyLink}">Take survey</a><br/>
|
||||
<br/>
|
||||
All the best,<br/>
|
||||
Your Formbricks Team 🤍`),
|
||||
});
|
||||
};
|
||||
|
||||
export const sendForgotPasswordEmail = async (user) => {
|
||||
const token = createToken(user.id, user.email, {
|
||||
expiresIn: "1d",
|
||||
});
|
||||
const verifyLink = `${WEBAPP_URL}/auth/forgot-password/reset?token=${encodeURIComponent(token)}`;
|
||||
await sendEmail({
|
||||
to: user.email,
|
||||
subject: "Reset your Formbricks password",
|
||||
html: withEmailTemplate(`<h1>Change password</h1>
|
||||
You have requested a link to change your password. You can do this by clicking the link below:<br/><br/>
|
||||
<a class="button" href="${verifyLink}">Change password</a><br/>
|
||||
<br/>
|
||||
<strong>The link is valid for 24 hours.</strong><br/><br/>If you didn't request this, please ignore this email.<br/>
|
||||
Your Formbricks Team`),
|
||||
});
|
||||
};
|
||||
|
||||
export const sendPasswordResetNotifyEmail = async (user) => {
|
||||
await sendEmail({
|
||||
to: user.email,
|
||||
subject: "Your Formbricks password has been changed",
|
||||
html: withEmailTemplate(`<h1>Password changed</h1>
|
||||
Your password has been changed successfully.<br/>
|
||||
<br/>
|
||||
Your Formbricks Team`),
|
||||
});
|
||||
};
|
||||
|
||||
export const sendInviteMemberEmail = async (inviteId, inviterName, inviteeName, email) => {
|
||||
const token = createInviteToken(inviteId, email, {
|
||||
expiresIn: "7d",
|
||||
});
|
||||
const verifyLink = `${WEBAPP_URL}/invite?token=${encodeURIComponent(token)}`;
|
||||
|
||||
await sendEmail({
|
||||
to: email,
|
||||
subject: `You're invited to collaborate on Formbricks!`,
|
||||
html: withEmailTemplate(`Hey ${inviteeName},<br/><br/>
|
||||
Your colleague ${inviterName} invited you to join them at Formbricks. To accept the invitation, please click the link below:<br/><br/>
|
||||
<a class="button" href="${verifyLink}">Join team</a><br/>
|
||||
<br/>
|
||||
Have a great day!<br/>
|
||||
The Formbricks Team!`),
|
||||
});
|
||||
};
|
||||
|
||||
export const sendInviteAcceptedEmail = async (inviterName, inviteeName, email) => {
|
||||
await sendEmail({
|
||||
to: email,
|
||||
subject: `You've got a new team member!`,
|
||||
html: withEmailTemplate(`Hey ${inviterName},
|
||||
<br/><br/>
|
||||
Just letting you know that ${inviteeName} accepted your invitation. Have fun collaborating!
|
||||
<br/><br/>
|
||||
Have a great day!<br/>
|
||||
The Formbricks Team!`),
|
||||
});
|
||||
};
|
||||
|
||||
export const sendResponseFinishedEmail = async (
|
||||
email: string,
|
||||
environmentId: string,
|
||||
survey: { id: string; name: string; questions: TSurveyQuestion[] },
|
||||
response: TResponse
|
||||
) => {
|
||||
const personEmail = response.person?.attributes["email"];
|
||||
await sendEmail({
|
||||
to: email,
|
||||
subject: personEmail
|
||||
? `${personEmail} just completed your ${survey.name} survey ✅`
|
||||
: `A response for ${survey.name} was completed ✅`,
|
||||
replyTo: personEmail?.toString() || MAIL_FROM,
|
||||
html: withEmailTemplate(`<h1>Hey 👋</h1>Someone just completed your survey <strong>${
|
||||
survey.name
|
||||
}</strong><br/>
|
||||
|
||||
<hr/>
|
||||
|
||||
${getQuestionResponseMapping(survey, response)
|
||||
.map(
|
||||
(question) =>
|
||||
question.answer &&
|
||||
`<div style="margin-top:1em;">
|
||||
<p style="margin:0px;">${question.question}</p>
|
||||
<p style="font-weight: 500; margin:0px; white-space:pre-wrap">${question.answer}</p>
|
||||
</div>`
|
||||
)
|
||||
.join("")}
|
||||
|
||||
|
||||
<a class="button" href="${WEBAPP_URL}/environments/${environmentId}/surveys/${
|
||||
survey.id
|
||||
}/responses?utm_source=emailnotification&utm_medium=email&utm_content=ViewResponsesCTA">View all responses</a>
|
||||
|
||||
<div class="tooltip">
|
||||
<p class='brandcolor'><strong>Start a conversation 💡</strong></p>
|
||||
${
|
||||
personEmail
|
||||
? `<p>Hit 'Reply' or reach out manually: ${personEmail}</p>`
|
||||
: "<p>If you set the email address as an attribute in in-app surveys, you can reply directly to the respondent.</p>"
|
||||
}
|
||||
</div>
|
||||
`),
|
||||
});
|
||||
};
|
||||
@@ -1,21 +1,12 @@
|
||||
"use server";
|
||||
|
||||
import { sendLinkSurveyToVerifiedEmail } from "@/app/lib/email";
|
||||
import { TSurveyPinValidationResponseError } from "@/app/s/[surveyId]/types";
|
||||
|
||||
import { LinkSurveyEmailData, sendLinkSurveyToVerifiedEmail } from "@formbricks/lib/emails/emails";
|
||||
import { verifyTokenForLinkSurvey } from "@formbricks/lib/jwt";
|
||||
import { getSurvey } from "@formbricks/lib/survey/service";
|
||||
import { TSurvey } from "@formbricks/types/surveys";
|
||||
|
||||
interface LinkSurveyEmailData {
|
||||
surveyId: string;
|
||||
email: string;
|
||||
surveyData?: {
|
||||
name?: string;
|
||||
subheading?: string;
|
||||
} | null;
|
||||
}
|
||||
|
||||
interface TSurveyPinValidationResponse {
|
||||
error?: TSurveyPinValidationResponseError;
|
||||
survey?: TSurvey;
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
import { TResponse } from "@formbricks/types/responses";
|
||||
import { TSurveyQuestion } from "@formbricks/types/surveys";
|
||||
|
||||
import { WEBAPP_URL } from "../constants";
|
||||
import { createInviteToken, createToken } from "../jwt";
|
||||
import {
|
||||
MAIL_FROM,
|
||||
SMTP_HOST,
|
||||
SMTP_PASSWORD,
|
||||
SMTP_PORT,
|
||||
SMTP_SECURE_ENABLED,
|
||||
SMTP_USER,
|
||||
WEBAPP_URL,
|
||||
} from "../constants";
|
||||
import { createInviteToken, createToken, createTokenForLinkSurvey } from "../jwt";
|
||||
import { getQuestionResponseMapping } from "../responses";
|
||||
import { withEmailTemplate } from "./email-template";
|
||||
|
||||
const nodemailer = require("nodemailer");
|
||||
|
||||
export const IS_SMTP_CONFIGURED: boolean =
|
||||
SMTP_HOST && SMTP_PORT && SMTP_USER && SMTP_PASSWORD ? true : false;
|
||||
|
||||
interface sendEmailData {
|
||||
to: string;
|
||||
replyTo?: string;
|
||||
@@ -21,22 +32,37 @@ interface TEmailUser {
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface LinkSurveyEmailData {
|
||||
surveyId: string;
|
||||
email: string;
|
||||
surveyData?: {
|
||||
name?: string;
|
||||
subheading?: string;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export const sendEmail = async (emailData: sendEmailData) => {
|
||||
let transporter = nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: process.env.SMTP_PORT,
|
||||
secure: process.env.SMTP_SECURE_ENABLED === "1", // true for 465, false for other ports
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASSWORD,
|
||||
},
|
||||
// logger: true,
|
||||
// debug: true,
|
||||
});
|
||||
const emailDefaults = {
|
||||
from: `Formbricks <${process.env.MAIL_FROM || "noreply@formbricks.com"}>`,
|
||||
};
|
||||
await transporter.sendMail({ ...emailDefaults, ...emailData });
|
||||
try {
|
||||
if (!IS_SMTP_CONFIGURED) throw new Error("Could not Email: SMTP not configured");
|
||||
|
||||
let transporter = nodemailer.createTransport({
|
||||
host: SMTP_HOST,
|
||||
port: SMTP_PORT,
|
||||
secure: SMTP_SECURE_ENABLED, // true for 465, false for other ports
|
||||
auth: {
|
||||
user: SMTP_USER,
|
||||
pass: SMTP_PASSWORD,
|
||||
},
|
||||
// logger: true,
|
||||
// debug: true,
|
||||
});
|
||||
const emailDefaults = {
|
||||
from: `Formbricks <${MAIL_FROM || "noreply@formbricks.com"}>`,
|
||||
};
|
||||
await transporter.sendMail({ ...emailDefaults, ...emailData });
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const sendVerificationEmail = async (user: TEmailUser) => {
|
||||
@@ -138,7 +164,7 @@ export const sendResponseFinishedEmail = async (
|
||||
subject: personEmail
|
||||
? `${personEmail} just completed your ${survey.name} survey ✅`
|
||||
: `A response for ${survey.name} was completed ✅`,
|
||||
replyTo: personEmail?.toString() || process.env.MAIL_FROM,
|
||||
replyTo: personEmail?.toString() || MAIL_FROM,
|
||||
html: withEmailTemplate(`<h1>Hey 👋</h1>Someone just completed your survey <strong>${
|
||||
survey.name
|
||||
}</strong><br/>
|
||||
@@ -151,7 +177,7 @@ export const sendResponseFinishedEmail = async (
|
||||
question.answer &&
|
||||
`<div style="margin-top:1em;">
|
||||
<p style="margin:0px;">${question.question}</p>
|
||||
<p style="font-weight: 500; margin:0px;">${question.answer}</p>
|
||||
<p style="font-weight: 500; margin:0px; white-space:pre-wrap">${question.answer}</p>
|
||||
</div>`
|
||||
)
|
||||
.join("")}
|
||||
@@ -164,7 +190,7 @@ export const sendResponseFinishedEmail = async (
|
||||
<p class='brandcolor'><strong>Start a conversation 💡</strong></p>
|
||||
${
|
||||
personEmail
|
||||
? "<p>Hit 'Reply' or reach out manually: ${personEmail}</p>"
|
||||
? `<p>Hit 'Reply' or reach out manually: ${personEmail}</p>`
|
||||
: "<p>If you set the email address as an attribute in in-app surveys, you can reply directly to the respondent.</p>"
|
||||
}
|
||||
</div>
|
||||
@@ -182,3 +208,23 @@ export const sendEmbedSurveyPreviewEmail = async (to: string, subject: string, h
|
||||
${html}`),
|
||||
});
|
||||
};
|
||||
|
||||
export const sendLinkSurveyToVerifiedEmail = async (data: LinkSurveyEmailData) => {
|
||||
const surveyId = data.surveyId;
|
||||
const email = data.email;
|
||||
const surveyData = data.surveyData;
|
||||
const token = createTokenForLinkSurvey(surveyId, email);
|
||||
const surveyLink = `${WEBAPP_URL}/s/${surveyId}?verify=${encodeURIComponent(token)}`;
|
||||
await sendEmail({
|
||||
to: data.email,
|
||||
subject: "Your Formbricks Survey",
|
||||
html: withEmailTemplate(`<h1>Hey 👋</h1>
|
||||
Thanks for validating your email. Here is your Survey.<br/><br/>
|
||||
<strong>${surveyData?.name}</strong>
|
||||
<p>${surveyData?.subheading}</p>
|
||||
<a class="button" href="${surveyLink}">Take survey</a><br/>
|
||||
<br/>
|
||||
All the best,<br/>
|
||||
Your Formbricks Team 🤍`),
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user