all repos — navani @ 11bda3a345132e4b9593ca939de1d57df28d0b09

forlater's primary mail processing service

Fix mail sending
Anirudh Oppiliappan x@icyphox.sh
Tue, 14 Sep 2021 17:00:35 +0530
commit

11bda3a345132e4b9593ca939de1d57df28d0b09

parent

860f7d536fa7b7bea67918d8dffda4fda0f9fb19

6 files changed, 89 insertions(+), 222 deletions(-)

jump to
M mail/send.gomail/send.go

@@ -5,7 +5,7 @@ "fmt"

"log" "os" - "github.com/go-shiori/go-readability" + "git.icyphox.sh/forlater/navani/reader" "github.com/joegrasse/mail" "github.com/joho/godotenv" )

@@ -17,7 +17,7 @@ log.Fatal("error loading .env file")

} } -func SendArticle(article *readability.Article, to string) error { +func SendArticle(article *reader.Article, to string) error { var ( EMAIL_USER_SECRET = os.Getenv("EMAIL_USER_SECRET") EMAIL_PASSWORD = os.Getenv("EMAIL_PASSWORD")

@@ -26,17 +26,22 @@ SMTP_HOST = os.Getenv("SMTP_HOST")

SMTP_PORT = os.Getenv("SMTP_PORT") ) + htmlContent, err := RenderTemplate("html.tpl", article) + if err != nil { + return err + } + email := mail.New() email.Encryption = mail.EncryptionTLS email.SetFrom(fmt.Sprintf("saved forlater <%s>", EMAIL_FROM)) email.AddTo(to) email.SetSubject(article.Title) email.SetBody("text/plain", article.TextContent) - email.AddAlternative("text/html", article.Content) + email.AddAlternative("text/html", string(htmlContent)) email.Username = EMAIL_USER_SECRET email.Password = EMAIL_PASSWORD - err := email.Send(SMTP_HOST + ":" + SMTP_PORT) + err = email.Send(SMTP_HOST + ":" + SMTP_PORT) if err != nil { return err }
A mail/template.go

@@ -0,0 +1,32 @@

+package mail + +import ( + "bytes" + "html/template" + "path/filepath" + + "git.icyphox.sh/forlater/navani/reader" +) + +func RenderTemplate(file string, article *reader.Article) ([]byte, error) { + t, err := template.ParseGlob(filepath.Join("templates", "*.tpl")) + if err != nil { + return nil, err + } + + buf := &bytes.Buffer{} + if err := t.ExecuteTemplate(buf, file, struct { + Content template.HTML + Title string + Byline string + URL string + }{ + template.HTML(article.Content), + article.Title, + article.Byline, + article.URL.String(), + }); err != nil { + return nil, err + } + return buf.Bytes(), nil +}
M main.gomain.go

@@ -40,6 +40,7 @@ if err != nil {

log.Println(err) } } + log.Printf("sent mail to %s\n", m.From) w.WriteHeader(204) })
M reader/fetch.goreader/fetch.go

@@ -1,6 +1,7 @@

package reader import ( + "bytes" "crypto/sha1" "encoding/hex" "fmt"

@@ -12,6 +13,11 @@

"git.icyphox.sh/forlater/navani/cache" readability "github.com/go-shiori/go-readability" ) + +type Article struct { + readability.Article + URL *url.URL +} func checksum(s []byte) string { h := sha1.New()

@@ -33,21 +39,27 @@ resp, err := http.Get(url)

if err != nil { return nil, err } - if b, err := io.ReadAll(resp.Body); err == nil { - c.Set(sum, b) + buf := bytes.Buffer{} + // Read into r and write into buf. + // Cache and return! + r := io.TeeReader(resp.Body, &buf) + b, err := io.ReadAll(r) + if err != nil { + c.Set(b) } - return resp.Body, nil + return &buf, nil } + return strings.NewReader(body), nil } // Makes a given html body readable. Returns an error if it // can't. -func Readable(r io.Reader, u *url.URL) (readability.Article, error) { +func Readable(r io.Reader, u *url.URL) (Article, error) { article, err := readability.FromReader(r, u) if err != nil { - return readability.Article{}, fmt.Errorf("failed to parse %s: %v\n", u, err) + return Article{}, fmt.Errorf("failed to parse %s: %v\n", u, err) } - return article, nil + return Article{article, u}, nil }
M templates/html.tpltemplates/html.tpl

@@ -4,178 +4,41 @@ <head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="x-apple-disable-message-reformatting"> - <title></title> - <style type="text/css"> - table, td { color: #000000; } @media only screen and (min-width: 520px) { - .u-row { - width: 500px !important; - } - .u-row .u-col { - vertical-align: top; - } - - .u-row .u-col-100 { - width: 500px !important; - } - -} - -@media (max-width: 520px) { - .u-row-container { - max-width: 100% !important; - padding-left: 0px !important; - padding-right: 0px !important; - } - .u-row .u-col { - min-width: 320px !important; - max-width: 100% !important; - display: block !important; - } - .u-row { - width: calc(100% - 40px) !important; - } - .u-col { - width: 100% !important; - } - .u-col > div { - margin: 0 auto; - } -} -body { - margin: 0; - padding: 0; -} - -table, -tr, -td { - vertical-align: top; - border-collapse: collapse; -} - -.ie-container table, -.mso-container table { - table-layout: fixed; -} + <style type="text/css"> + img, video { + align: center; + object-fit: cover; + width: 400px; + height: 200px; + } -* { - line-height: inherit; -} + body { + margin: 0; + padding: 0; + max-width: 640px; + } + a[x-apple-data-detectors='true'] { + color: inherit !important; + text-decoration: none !important; + } -a[x-apple-data-detectors='true'] { - color: inherit !important; - text-decoration: none !important; -} - -</style> + .page { + font-family: serif; + } + </style> </head> -<body class="clean-body" style="margin: 0;padding: 0;-webkit-text-size-adjust: 100%;background-color: #f4f4f4;color: #000000"> - <!--[if IE]><div class="ie-container"><![endif]--> - <!--[if mso]><div class="mso-container"><![endif]--> - <table style="border-collapse: collapse;table-layout: fixed;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;vertical-align: top;min-width: 320px;Margin: 0 auto;background-color: #f4f4f4;width:100%" cellpadding="0" cellspacing="0"> - <tbody> - <tr style="vertical-align: top"> - <td style="word-break: break-word;border-collapse: collapse !important;vertical-align: top"> - <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td align="center" style="background-color: #f4f4f4;"><![endif]--> - - -<div class="u-row-container" style="padding: 0px;background-color: transparent"> - <div class="u-row" style="Margin: 0 auto;min-width: 320px;max-width: 500px;overflow-wrap: break-word;word-wrap: break-word;word-break: break-word;background-color: transparent;"> - <div style="border-collapse: collapse;display: table;width: 100%;background-color: transparent;"> - <!--[if (mso)|(IE)]><table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td style="padding: 0px;background-color: transparent;" align="center"><table cellpadding="0" cellspacing="0" border="0" style="width:500px;"><tr style="background-color: transparent;"><![endif]--> - -<!--[if (mso)|(IE)]><td align="center" width="500" style="width: 500px;padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;" valign="top"><![endif]--> -<div class="u-col u-col-100" style="max-width: 320px;min-width: 500px;display: table-cell;vertical-align: top;"> - <div style="width: 100% !important;"> - <!--[if (!mso)&(!IE)]><!--><div style="padding: 0px;border-top: 0px solid transparent;border-left: 0px solid transparent;border-right: 0px solid transparent;border-bottom: 0px solid transparent;"><!--<![endif]--> - -<table style="font-family:serif;" role="presentation" cellpadding="0" cellspacing="0" width="100%" border="0"> - <tbody> - <tr> - <td style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:serif;" align="left"> - - <h1 style="margin: 0px; line-height: 140%; text-align: left; word-wrap: break-word; font-weight: normal; font-family: serif; font-size: 22px;"> - {{ .Heading }} +<body> + <em>original link</em>: <a href="{{ .URL }}">{{ .URL }}</a> + <h1> + {{ .Title }} </h1> - - </td> - </tr> - </tbody> -</table> - -<table style="font-family:serif;" role="presentation" cellpadding="0" cellspacing="0" width="100%" border="0"> - <tbody> - <tr> - <td style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:serif;" align="left"> - - <table height="0px" align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;table-layout: fixed;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;vertical-align: top;border-top: 1px solid #BBBBBB;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%"> - <tbody> - <tr style="vertical-align: top"> - <td style="word-break: break-word;border-collapse: collapse !important;vertical-align: top;font-size: 0px;line-height: 0px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%"> - <span>&#160;</span> - </td> - </tr> - </tbody> - </table> - - </td> - </tr> - </tbody> -</table> - -<table style="font-family:serif;" role="presentation" cellpadding="0" cellspacing="0" width="100%" border="0"> - <tbody> - <tr> - <td style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:serif;" align="left"> -<!-- main content --> - <div> - {{ .Body }} - </div> - - </td> - </tr> - </tbody> -</table> - -<table style="font-family:serif;" role="presentation" cellpadding="0" cellspacing="0" width="100%" border="0"> - <tbody> - <tr> - <td style="overflow-wrap:break-word;word-break:break-word;padding:10px;font-family:serif;" align="left"> - - <table height="0px" align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="border-collapse: collapse;table-layout: fixed;border-spacing: 0;mso-table-lspace: 0pt;mso-table-rspace: 0pt;vertical-align: top;border-top: 1px solid #BBBBBB;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%"> - <tbody> - <tr style="vertical-align: top"> - <td style="word-break: break-word;border-collapse: collapse !important;vertical-align: top;font-size: 0px;line-height: 0px;mso-line-height-rule: exactly;-ms-text-size-adjust: 100%;-webkit-text-size-adjust: 100%"> - <span>&#160;</span> - </td> - </tr> - </tbody> - </table> - - </td> - </tr> - </tbody> -</table> - - <!--[if (!mso)&(!IE)]><!--></div><!--<![endif]--> - </div> -</div> -<!--[if (mso)|(IE)]></td><![endif]--> - <!--[if (mso)|(IE)]></tr></table></td></tr></table><![endif]--> - </div> - </div> -</div> - - - <!--[if (mso)|(IE)]></td></tr></table><![endif]--> - </td> - </tr> - </tbody> - </table> - <!--[if mso]></div><![endif]--> - <!--[if IE]></div><![endif]--> + <h2> + {{ .Byline }} + </h2> + <hr> + {{ .Content }} </body> </html>
D templates/index.html

@@ -1,46 +0,0 @@

-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html> - <head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0"/> - <meta name="x-apple-disable-message-reformatting"> - </head> - <body> - <p class="wrapper"> - Test - </p> - </body> -</html> -<style> - body,table,thead,tbody,tr,td,img { - padding: 0; - margin: 0; - border: none; - border-spacing: 0px; - border-collapse: collapse; - vertical-align: top; - } - - /* Add some padding for small screens */ - .wrapper { - padding-left: 10px; - padding-right: 10px; - } - - h1,h2,h3,h4,h5,h6,p { - margin: 0; - padding: 0; - padding-bottom: 20px; - line-height: 1.6; - font-family: serif; - } - - p,a,li { - font-family: serif; - } - - img { - width: 100%; - display: block; - } -</style>