81 lines
1.9 KiB
Go
81 lines
1.9 KiB
Go
package email
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/PuerkitoBio/goquery"
|
|
)
|
|
|
|
// htmlToPlainText derives a plain-text representation from rendered HTML.
|
|
// The text version is for email clients that cannot render HTML. The HTML
|
|
// version is always preferred when the client supports it.
|
|
func htmlToPlainText(htmlStr string) string {
|
|
doc, err := goquery.NewDocumentFromReader(strings.NewReader(htmlStr))
|
|
if err != nil {
|
|
return htmlStr
|
|
}
|
|
|
|
// Remove elements that should not appear in plain text.
|
|
doc.Find("style, script, head, .preheader").Remove()
|
|
|
|
// Replace links with "text (URL)" format.
|
|
doc.Find("a[href]").Each(func(_ int, s *goquery.Selection) {
|
|
href, _ := s.Attr("href")
|
|
text := strings.TrimSpace(s.Text())
|
|
if href != "" && href != text && !strings.HasPrefix(href, "mailto:") {
|
|
s.ReplaceWithHtml(text + "\n" + href)
|
|
}
|
|
})
|
|
|
|
// Walk the DOM and collect text with structural newlines.
|
|
var lines []string
|
|
var walk func(*goquery.Selection)
|
|
walk = func(sel *goquery.Selection) {
|
|
sel.Contents().Each(func(_ int, n *goquery.Selection) {
|
|
tag := goquery.NodeName(n)
|
|
switch tag {
|
|
case "#text":
|
|
t := strings.TrimSpace(n.Text())
|
|
if t != "" {
|
|
lines = append(lines, t)
|
|
}
|
|
case "br":
|
|
lines = append(lines, "")
|
|
case "p", "div", "section", "article", "main", "h1", "h2", "h3", "h4", "h5", "h6", "li":
|
|
walk(n)
|
|
lines = append(lines, "")
|
|
case "tr":
|
|
walk(n)
|
|
lines = append(lines, "")
|
|
case "hr":
|
|
lines = append(lines, "---")
|
|
default:
|
|
walk(n)
|
|
}
|
|
})
|
|
}
|
|
|
|
body := doc.Find("body")
|
|
if body.Length() == 0 {
|
|
body = doc.Selection
|
|
}
|
|
walk(body)
|
|
|
|
// Collapse consecutive blank lines to a single blank line.
|
|
result := make([]string, 0, len(lines))
|
|
prevBlank := false
|
|
for _, line := range lines {
|
|
if line == "" {
|
|
if !prevBlank {
|
|
result = append(result, "")
|
|
}
|
|
prevBlank = true
|
|
} else {
|
|
result = append(result, line)
|
|
prevBlank = false
|
|
}
|
|
}
|
|
|
|
return strings.TrimSpace(strings.Join(result, "\n"))
|
|
}
|