Add initial onboard email
...and patterns for how to do email stuff in the future.
This commit is contained in:
parent
aa7585563b
commit
44fdaa6c2b
10 changed files with 205 additions and 31 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
97
comms/template/initial.html
Normal file
97
comms/template/initial.html
Normal 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>© 2026 Gleipnir LLC. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
1
comms/template/initial.txt
Normal file
1
comms/template/initial.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
Welcome to Report Mosquitoes Online.
|
||||
Loading…
Add table
Add a link
Reference in a new issue