Compare commits

...

1 Commits

Author SHA1 Message Date
Tiago Farto e79cbf549c fix(email): improve Outlook preview markup 2026-04-21 14:44:20 +00:00
3 changed files with 42 additions and 10 deletions
@@ -0,0 +1,28 @@
import { describe, expect, test } from "vitest";
import { extractEmailBodyFragment } from "./emailTemplate";
describe("extractEmailBodyFragment", () => {
test("returns the body contents for rendered email documents", () => {
const html = `
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<style>.foo { color: red; }</style>
</head>
<body class="email-body">
<table>
<tr>
<td>Preview content</td>
</tr>
</table>
</body>
</html>
`;
expect(extractEmailBodyFragment(html)).toBe("<table>\n <tr>\n <td>Preview content</td>\n </tr>\n </table>");
});
test("falls back to the original markup when no body tag exists", () => {
expect(extractEmailBodyFragment("<div>Preview content</div>")).toBe("<div>Preview content</div>");
});
});
@@ -6,6 +6,16 @@ import { getStyling } from "@/lib/utils/styling";
import { getTranslate } from "@/lingodotdev/server";
import { getPreviewEmailTemplateHtml } from "@/modules/email/components/preview-email-template";
const EMAIL_DOCTYPE_PATTERN = /<!DOCTYPE[^>]*>/i;
const EMAIL_BODY_PATTERN = /<body\b[^>]*>([\s\S]*?)<\/body>/i;
export const extractEmailBodyFragment = (html: string): string => {
const htmlWithoutDoctype = html.replace(EMAIL_DOCTYPE_PATTERN, "").trim();
const bodyMatch = htmlWithoutDoctype.match(EMAIL_BODY_PATTERN);
return bodyMatch?.[1].trim() ?? htmlWithoutDoctype;
};
export const getEmailTemplateHtml = async (surveyId: string, locale: string) => {
const t = await getTranslate();
const survey = await getSurvey(surveyId);
@@ -20,9 +30,6 @@ export const getEmailTemplateHtml = async (surveyId: string, locale: string) =>
const styling = getStyling(project, survey);
const surveyUrl = getPublicDomain() + "/s/" + survey.id;
const html = await getPreviewEmailTemplateHtml(survey, surveyUrl, styling, locale, t);
const doctype =
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
const htmlCleaned = html.toString().replace(doctype, "");
return htmlCleaned;
return extractEmailBodyFragment(html.toString());
};
@@ -442,7 +442,7 @@ export async function PreviewEmailTemplate({
function EmailTemplateWrapper({
children,
surveyUrl,
surveyUrl: _surveyUrl,
styling,
}: {
children: React.ReactNode;
@@ -480,12 +480,9 @@ function EmailTemplateWrapper({
},
},
}}>
<Link
className="bg-card-bg-color border-card-border-color rounded-custom mx-0 my-2 block overflow-auto border border-solid p-8 font-sans text-inherit"
href={surveyUrl}
target="_blank">
<Section className="bg-card-bg-color border-card-border-color rounded-custom mx-0 my-2 border border-solid p-8 font-sans text-inherit">
{children}
</Link>
</Section>
</Tailwind>
);
}