Hello {{.Data.Name}}, This is a reminder that your API key {{.Data.APIKeyName}} will expire on {{.Data.ExpiresAt.Format "2006-01-02 15:04:05 MST"}}.
Please generate a new API key if you need continued access.
{{end}}
\ No newline at end of file
+{{define "root"}}
{{.AppName}}
API Key Expiring Soon
Warning
Hello {{.Data.Name}}, This is a reminder that your API key {{.Data.APIKeyName}} will expire on {{.Data.ExpiresAt.Format "2006-01-02 15:04:05 MST"}}.
Please generate a new API key if you need continued access.
{{end}}
\ No newline at end of file
diff --git a/backend/resources/email-templates/login-with-new-device_html.tmpl b/backend/resources/email-templates/login-with-new-device_html.tmpl
index 85d2e4dc..c91a7ea1 100644
--- a/backend/resources/email-templates/login-with-new-device_html.tmpl
+++ b/backend/resources/email-templates/login-with-new-device_html.tmpl
@@ -1,5 +1 @@
-{{define "root"}}
-
{{.AppName}}
New Sign-In Detected
-
Warning
Your {{.AppName}} account was recently accessed from a new IP address or browser. If you recognize this activity, no further action is required.
Details
Approximate Location
-
{{if and .Data.City .Data.Country}}{{.Data.City}}, {{.Data.Country}}{{else if .Data.Country}}{{.Data.Country}}{{else}}Unknown{{end}}
IP Address
{{.Data.IPAddress}}
Device
-
{{.Data.Device}}
Sign-In Time
{{.Data.DateTime.Format "January 2, 2006 at 3:04 PM MST"}}
{{end}}
\ No newline at end of file
+{{define "root"}}
{{.AppName}}
New Sign-In Detected
Warning
Your {{.AppName}} account was recently accessed from a new IP address or browser. If you recognize this activity, no further action is required.
Details
Approximate Location
{{if and .Data.City .Data.Country}}{{.Data.City}}, {{.Data.Country}}{{else if .Data.Country}}{{.Data.Country}}{{else}}Unknown{{end}}
IP Address
{{.Data.IPAddress}}
Device
{{.Data.Device}}
Sign-In Time
{{.Data.DateTime.Format "January 2, 2006 at 3:04 PM MST"}}
{{end}}
\ No newline at end of file
diff --git a/backend/resources/email-templates/one-time-access_html.tmpl b/backend/resources/email-templates/one-time-access_html.tmpl
index ba0ae8c4..6b6fb0b6 100644
--- a/backend/resources/email-templates/one-time-access_html.tmpl
+++ b/backend/resources/email-templates/one-time-access_html.tmpl
@@ -1,4 +1 @@
-{{define "root"}}
-
{{.AppName}}
Your Login Code
Click the button below to sign in to
-{{.AppName}} with a login code. Or visit {{.Data.LoginLink}} and enter the code {{.Data.Code}}.
{{end}}
\ No newline at end of file
diff --git a/backend/resources/email-templates/test_html.tmpl b/backend/resources/email-templates/test_html.tmpl
index 34a720d0..21a4bdde 100644
--- a/backend/resources/email-templates/test_html.tmpl
+++ b/backend/resources/email-templates/test_html.tmpl
@@ -1,3 +1 @@
-{{define "root"}}
-
{{.AppName}}
Test Email
Your email setup is working correctly!
-
{{end}}
\ No newline at end of file
+{{define "root"}}
{{.AppName}}
Test Email
Your email setup is working correctly!
{{end}}
\ No newline at end of file
diff --git a/email-templates/build.ts b/email-templates/build.ts
index c8b86e76..3c235918 100644
--- a/email-templates/build.ts
+++ b/email-templates/build.ts
@@ -12,40 +12,6 @@ function getTemplateName(filename: string): string {
return filename.replace(".tsx", "");
}
-/**
- * Tag-aware wrapping:
- * - Prefer breaking immediately after the last '>' within maxLen.
- * - Never break at spaces.
- * - If no '>' exists in the window, hard-break at maxLen.
- */
-function tagAwareWrap(input: string, maxLen: number): string {
- const out: string[] = [];
-
- for (const originalLine of input.split(/\r?\n/)) {
- let line = originalLine;
- while (line.length > maxLen) {
- let breakPos = line.lastIndexOf(">", maxLen);
-
- // If '>' happens to be exactly at maxLen, break after it
- if (breakPos === maxLen) breakPos = maxLen;
-
- // If we found a '>' before the limit, break right after it
- if (breakPos > -1 && breakPos < maxLen) {
- out.push(line.slice(0, breakPos + 1));
- line = line.slice(breakPos + 1);
- continue;
- }
-
- // No suitable tag end found—hard break
- out.push(line.slice(0, maxLen));
- line = line.slice(maxLen);
- }
- out.push(line);
- }
-
- return out.join("\n");
-}
-
async function buildTemplateFile(
Component: any,
templateName: string,
@@ -58,11 +24,7 @@ async function buildTemplateFile(
// Normalize quotes
const normalized = rendered.replace(/"/g, '"');
- // Enforce line length: prefer tag boundaries, never spaces
- const maxLen = isPlainText ? 78 : 998; // RFC-safe
- const safe = tagAwareWrap(normalized, maxLen);
-
- const goTemplate = `{{define "root"}}${safe}{{end}}`;
+ const goTemplate = `{{define "root"}}${normalized}{{end}}`;
const suffix = isPlainText ? "_text.tmpl" : "_html.tmpl";
const templatePath = path.join(outputDir, `${templateName}${suffix}`);
@@ -98,7 +60,7 @@ async function discoverAndBuildTemplates() {
}
await buildTemplateFile(Component, templateName, false); // HTML
- await buildTemplateFile(Component, templateName, true); // Text
+ await buildTemplateFile(Component, templateName, true); // Text
console.log(`✓ Built ${templateName}`);
} catch (error) {
@@ -112,4 +74,4 @@ async function main() {
console.log("All templates built successfully!");
}
-main().catch(console.error);
\ No newline at end of file
+main().catch(console.error);