Add initial onboard email

...and patterns for how to do email stuff in the future.
This commit is contained in:
Eli Ribble 2026-01-23 02:50:25 +00:00
parent aa7585563b
commit 44fdaa6c2b
No known key found for this signature in database
10 changed files with 205 additions and 31 deletions

View file

@ -13,13 +13,39 @@ import (
"github.com/rs/zerolog/log"
)
func RenderEmailInitial(w http.ResponseWriter, destination string) {
content := newContentEmailInitial(destination)
renderOrError(w, initialT, content)
}
func RenderEmailReportConfirmation(w http.ResponseWriter, report_id string) {
content := contentEmailSubscriptionConfirmation(report_id)
content := newContentEmailSubscriptionConfirmation(report_id)
renderOrError(w, reportConfirmationT, content)
}
func SendEmailInitialContact(destination string) error {
content := newContentEmailInitial(destination)
text, html, err := renderEmailTemplates(reportConfirmationT, content)
if err != nil {
return fmt.Errorf("Failed to render email temlate: %w", err)
}
resp, err := sendEmail(emailRequest{
From: config.ForwardEmailReportAddress,
HTML: html,
Subject: "Welcome",
Text: text,
To: destination,
})
if err != nil {
return fmt.Errorf("Failed to send email to %s: %w", err)
}
log.Info().Str("id", resp.ID).Str("to", destination).Msg("Sent initial contact email")
return nil
}
func SendEmailReportConfirmation(to string, report_id string) error {
report_id_str := publicReportID(report_id)
content := contentEmailSubscriptionConfirmation(report_id)
content := newContentEmailSubscriptionConfirmation(report_id)
text, html, err := renderEmailTemplates(reportConfirmationT, content)
if err != nil {
return fmt.Errorf("Failed to render template %s: %w", reportConfirmationT.name, err)
@ -39,6 +65,7 @@ func SendEmailReportConfirmation(to string, report_id string) error {
}
var (
initialT = buildTemplate("initial")
reportConfirmationT = buildTemplate("report-subscription-confirmation")
)
@ -50,11 +77,20 @@ type attachmentRequest struct {
Content string `json:"content"`
}
type contentEmailBase struct {
URLLogo string
URLUnsubscribe string
URLViewInBrowser string
}
type contentEmailReportConfirmation struct {
URLLogo string
URLReportStatus string
URLReportUnsubscribe string
URLViewInBrowser string
Base contentEmailBase
URLReportStatus string
}
type contentEmailInitial struct {
Base contentEmailBase
Destination string
URLSubscribe string
}
type emailRequest struct {
@ -104,13 +140,28 @@ type emailResponse struct {
Message string `json:"message"`
}
func contentEmailSubscriptionConfirmation(report_id string) contentEmailReportConfirmation {
return contentEmailReportConfirmation{
URLLogo: config.MakeURLReport("/static/img/nidus-logo-no-lettering-64.png"),
URLReportStatus: config.MakeURLReport("/status/%s", report_id),
URLReportUnsubscribe: config.MakeURLReport("/report/%s/unsubscribe", report_id),
URLViewInBrowser: config.MakeURLReport("/email/report/%s/subscription-confirmation", report_id),
}
func newContentBase(b *contentEmailBase, url string) {
b.URLLogo = config.MakeURLReport("/static/img/nidus-logo-no-lettering-64.png")
b.URLUnsubscribe = config.MakeURLReport("/email/unsubscribe")
b.URLViewInBrowser = url
}
func newContentEmailInitial(destination string) (result contentEmailInitial) {
newContentBase(
&result.Base,
config.MakeURLReport("/email/initial"),
)
result.Destination = destination
result.URLSubscribe = config.MakeURLReport("/email/subscribe?email=%s", destination)
return result
}
func newContentEmailSubscriptionConfirmation(report_id string) (result contentEmailReportConfirmation) {
newContentBase(
&result.Base,
config.MakeURLReport("/email/report/%s/subscription-confirmation", report_id),
)
result.URLReportStatus = config.MakeURLReport("/status/%s", report_id)
return result
}
func publicReportID(s string) string {

View file

@ -0,0 +1,97 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Welcome</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
font-size: 16px;
line-height: 1.5;
color: #333333;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.view-browser {
text-align: center;
font-size: 12px;
color: #777777;
padding-bottom: 15px;
}
.view-browser a {
color: #555555;
text-decoration: underline;
}
.header {
text-align: center;
padding: 20px 0;
}
.logo {
max-width: 150px;
height: auto;
}
.content {
background-color: #f9f9f9;
padding: 30px;
border-radius: 5px;
}
.button {
display: inline-block;
background-color: #0066cc;
color: #ffffff;
text-decoration: none;
padding: 12px 25px;
border-radius: 4px;
margin: 20px 0;
font-weight: bold;
}
.footer {
text-align: center;
font-size: 14px;
color: #777777;
padding: 20px 0;
}
.footer a {
color: #777777;
}
</style>
</head>
<body>
<div class="container">
<div class="view-browser">
Email not displaying correctly? <a href="{{.Base.URLViewInBrowser}}">View it in your browser</a>
</div>
<div class="header">
<!-- Logo Placeholder -->
<img src="{{.Base.URLLogo}}" alt="Report Mosquitoes Online Logo" class="logo"></img>
</div>
<div class="content">
<h1>Welcome</h1>
<p>We're sending you this email because it's the first time we've gotten this email address ({{.Destination}}).</p>
<p>If you'd rather not receive emails from us you can reply with "Unsubscribe" in the subject or body of the email. You can also use the "Unsubscribe" feature of your mail client, if it supports list unsubscribes.</p>
<p>If instead you'd like to confirm that you're willing to receive emails at this address, you can do so by clicking below:</p>
<div style="text-align: center;">
<a href="{{.Base.URLSubscribe}}" class="button">I want emails from Report Mosquitoes Online</a>
</div>
</div>
<div class="footer">
<p>This email was sent to you because you or someone else gave your email address to Report Mosquitoes Online.</p>
<p>If you no longer wish to receive these updates, <a href="{{.Base.URLUnsubscribe}}">click here to unsubscribe</a>.</p>
<p>&copy; 2026 Gleipnir LLC. All rights reserved.</p>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1 @@
Welcome to Report Mosquitoes Online.