1
0
forked from wrenn/wrenn

Add transactional email system via SMTP

Introduce internal/email package with SMTP sending, embedded HTML/text
templates, and multipart MIME assembly. Emails use a generic EmailData
struct (recipient name, message, optional button, optional closing) so
new email types can be added without code changes.

Wired into signup (welcome email), team creation, and team member
addition. No-op mailer when SMTP_HOST is not configured.
This commit is contained in:
2026-04-16 00:46:08 +06:00
parent 700512b627
commit 9d68eb5f00
12 changed files with 697 additions and 9 deletions

View File

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Wrenn</title>
<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<style type="text/css">
body, table, td, a { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
img { -ms-interpolation-mode: bicubic; border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; }
body { margin: 0; padding: 0; width: 100% !important; }
</style>
</head>
<body style="margin: 0; padding: 0; background-color: #f4f3f1; font-family: 'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased;">
<!-- Outer wrapper -->
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background-color: #f4f3f1;">
<tr>
<td align="center" style="padding: 40px 16px;">
<!-- Logo -->
<table role="presentation" cellpadding="0" cellspacing="0" width="560" style="max-width: 560px;">
<tr>
<td align="left" style="padding-bottom: 24px;">
<a href="https://wrenn.dev" style="text-decoration: none;">
<img src="https://wrenn.dev/logo.png" alt="Wrenn" width="36" height="36" style="display: block; border-radius: 6px;">
</a>
</td>
</tr>
</table>
<!-- Card -->
<table role="presentation" cellpadding="0" cellspacing="0" width="560" style="max-width: 560px; background-color: #ffffff; border: 1px solid #e5e4e0; border-radius: 8px;">
<tr>
<td style="padding: 40px 44px;">
<!-- Greeting -->
{{if .RecipientName}}
<p style="margin: 0 0 20px 0; font-size: 15px; line-height: 1.6; color: #3a3835;">
Hello {{.RecipientName}},
</p>
{{end}}
<!-- Message -->
<p style="margin: 0 0 24px 0; font-size: 15px; line-height: 1.7; color: #3a3835;">
{{.Message}}
</p>
<!-- Button -->
{{if .Button}}
<table role="presentation" cellpadding="0" cellspacing="0" style="margin: 28px 0;">
<tr>
<td align="center" style="background-color: #5e8c58; border-radius: 5px;">
<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="{{.Button.URL}}" style="height:44px;v-text-anchor:middle;width:200px;" arcsize="12%" strokecolor="#5e8c58" fillcolor="#5e8c58">
<w:anchorlock/>
<center style="color:#ffffff;font-family:'Manrope',-apple-system,sans-serif;font-size:14px;font-weight:600;">{{.Button.Text}}</center>
</v:roundrect>
<![endif]-->
<!--[if !mso]><!-->
<a href="{{.Button.URL}}" target="_blank" style="display: inline-block; padding: 12px 28px; font-size: 14px; font-weight: 600; color: #ffffff; text-decoration: none; border-radius: 5px; background-color: #5e8c58;">
{{.Button.Text}}
</a>
<!--<![endif]-->
</td>
</tr>
</table>
<p style="margin: 0 0 24px 0; font-size: 13px; line-height: 1.6; color: #9b9790;">
If the button doesn't work, copy and paste this URL into your browser:<br>
<a href="{{.Button.URL}}" style="color: #5e8c58; word-break: break-all;">{{.Button.URL}}</a>
</p>
{{end}}
<!-- Closing -->
{{if .Closing}}
<p style="margin: 0; font-size: 15px; line-height: 1.7; color: #3a3835;">
{{.Closing}}
</p>
{{end}}
</td>
</tr>
</table>
<!-- Footer -->
<table role="presentation" cellpadding="0" cellspacing="0" width="560" style="max-width: 560px;">
<tr>
<td style="padding: 24px 0; text-align: center;">
<p style="margin: 0; font-size: 12px; line-height: 1.5; color: #9b9790;">
This is a transactional email from <a href="https://wrenn.dev" style="color: #5e8c58; text-decoration: none;">Wrenn</a>.
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>

View File

@ -0,0 +1,13 @@
{{if .RecipientName}}Hello {{.RecipientName}},
{{end}}{{.Message}}
{{if .Button}}
{{.Button.Text}}: {{.Button.URL}}
{{end}}{{if .Closing}}
{{.Closing}}
{{end}}
---
This is a transactional email from Wrenn (https://wrenn.dev).