225 lines
7.1 KiB
Go
225 lines
7.1 KiB
Go
|
package googleapi
|
||
|
|
||
|
import (
|
||
|
"gogs.mikescher.com/BlackForestBytes/goext/langext"
|
||
|
"mime"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// https://datatracker.ietf.org/doc/html/rfc2822
|
||
|
func encodeMimeMail(from string, recipients []string, cc []string, bcc []string, subject string, body MailBody, attachments []MailAttachment) string {
|
||
|
|
||
|
data := make([]string, 0, 32)
|
||
|
|
||
|
data = append(data, "Date: "+time.Now().Format(time.RFC1123Z))
|
||
|
data = append(data, "MIME-Version: 1.0")
|
||
|
data = append(data, "From: "+mime.QEncoding.Encode("UTF-8", from))
|
||
|
data = append(data, "To: "+strings.Join(langext.ArrMap(recipients, func(v string) string { return mime.QEncoding.Encode("UTF-8", v) }), ", "))
|
||
|
if len(cc) > 0 {
|
||
|
data = append(data, "To: "+strings.Join(langext.ArrMap(cc, func(v string) string { return mime.QEncoding.Encode("UTF-8", v) }), ", "))
|
||
|
}
|
||
|
if len(bcc) > 0 {
|
||
|
data = append(data, "Bcc: "+strings.Join(langext.ArrMap(bcc, func(v string) string { return mime.QEncoding.Encode("UTF-8", v) }), ", "))
|
||
|
}
|
||
|
data = append(data, "Subject: "+mime.QEncoding.Encode("UTF-8", subject))
|
||
|
|
||
|
hasInlineAttachments := langext.ArrAny(attachments, func(v MailAttachment) bool { return v.IsInline })
|
||
|
hasNormalAttachments := langext.ArrAny(attachments, func(v MailAttachment) bool { return !v.IsInline })
|
||
|
hasPlain := body.Plain != ""
|
||
|
hasHTML := body.HTML != ""
|
||
|
|
||
|
mixedBoundary := langext.MustRawHexUUID()
|
||
|
relatedBoundary := langext.MustRawHexUUID()
|
||
|
altBoundary := langext.MustRawHexUUID()
|
||
|
|
||
|
inlineAttachments := langext.ArrFilter(attachments, func(v MailAttachment) bool { return v.IsInline })
|
||
|
normalAttachments := langext.ArrFilter(attachments, func(v MailAttachment) bool { return !v.IsInline })
|
||
|
|
||
|
if hasInlineAttachments && hasNormalAttachments {
|
||
|
// "mixed+related"
|
||
|
|
||
|
data = append(data, "Content-Type: multipart/mixed; boundary="+mixedBoundary)
|
||
|
data = append(data, "")
|
||
|
data = append(data, "--"+mixedBoundary)
|
||
|
|
||
|
data = append(data, "Content-Type: multipart/related; boundary="+relatedBoundary)
|
||
|
data = append(data, "")
|
||
|
|
||
|
data = append(data, dumpMailBody(body, hasInlineAttachments, hasNormalAttachments, relatedBoundary, altBoundary)...)
|
||
|
data = append(data, "")
|
||
|
|
||
|
for i, attachment := range inlineAttachments {
|
||
|
data = append(data, "--"+relatedBoundary)
|
||
|
data = append(data, attachment.dump()...)
|
||
|
|
||
|
if i < len(inlineAttachments)-1 {
|
||
|
data = append(data, "")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
data = append(data, "--"+relatedBoundary+"--")
|
||
|
|
||
|
for i, attachment := range normalAttachments {
|
||
|
data = append(data, "--"+mixedBoundary)
|
||
|
data = append(data, attachment.dump()...)
|
||
|
|
||
|
if i < len(normalAttachments)-1 {
|
||
|
data = append(data, "")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
data = append(data, "--"+mixedBoundary+"--")
|
||
|
|
||
|
} else if hasNormalAttachments {
|
||
|
// "mixed"
|
||
|
|
||
|
data = append(data, "Content-Type: multipart/mixed; boundary="+mixedBoundary)
|
||
|
data = append(data, "")
|
||
|
|
||
|
data = append(data, dumpMailBody(body, hasInlineAttachments, hasNormalAttachments, mixedBoundary, altBoundary)...)
|
||
|
if hasPlain && hasHTML {
|
||
|
data = append(data, "")
|
||
|
}
|
||
|
|
||
|
for i, attachment := range normalAttachments {
|
||
|
data = append(data, "--"+mixedBoundary)
|
||
|
data = append(data, attachment.dump()...)
|
||
|
|
||
|
if i < len(normalAttachments)-1 {
|
||
|
data = append(data, "")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
data = append(data, "--"+mixedBoundary+"--")
|
||
|
|
||
|
} else if hasInlineAttachments {
|
||
|
// "related"
|
||
|
|
||
|
data = append(data, "Content-Type: multipart/related; boundary="+relatedBoundary)
|
||
|
data = append(data, "")
|
||
|
|
||
|
data = append(data, dumpMailBody(body, hasInlineAttachments, hasNormalAttachments, relatedBoundary, altBoundary)...)
|
||
|
data = append(data, "")
|
||
|
|
||
|
for i, attachment := range inlineAttachments {
|
||
|
data = append(data, "--"+relatedBoundary)
|
||
|
data = append(data, attachment.dump()...)
|
||
|
|
||
|
if i < len(inlineAttachments)-1 {
|
||
|
data = append(data, "")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
data = append(data, "--"+relatedBoundary+"--")
|
||
|
|
||
|
} else if hasPlain && hasHTML {
|
||
|
// "alternative"
|
||
|
|
||
|
data = append(data, "Content-Type: multipart/alternative; boundary="+altBoundary)
|
||
|
data = append(data, "")
|
||
|
|
||
|
data = append(data, dumpMailBody(body, hasInlineAttachments, hasNormalAttachments, altBoundary, altBoundary)...)
|
||
|
data = append(data, "")
|
||
|
|
||
|
data = append(data, "--"+altBoundary+"--")
|
||
|
|
||
|
} else if hasPlain {
|
||
|
// "plain"
|
||
|
|
||
|
data = append(data, "Content-Type: text/plain; charset=UTF-8")
|
||
|
data = append(data, "Content-Transfer-Encoding: 7bit")
|
||
|
data = append(data, "")
|
||
|
data = append(data, body.Plain)
|
||
|
|
||
|
} else if hasHTML {
|
||
|
// "plain"
|
||
|
|
||
|
data = append(data, "Content-Type: text/html; charset=UTF-8")
|
||
|
data = append(data, "Content-Transfer-Encoding: 7bit")
|
||
|
data = append(data, "")
|
||
|
data = append(data, body.HTML)
|
||
|
|
||
|
} else {
|
||
|
// "empty??"
|
||
|
|
||
|
}
|
||
|
|
||
|
return strings.Join(data, "\r\n")
|
||
|
}
|
||
|
|
||
|
func dumpMailBody(body MailBody, hasInlineAttachments bool, hasNormalAttachments bool, boundary string, boundaryAlt string) []string {
|
||
|
|
||
|
if body.HTML != "" && body.Plain != "" && !hasInlineAttachments && hasNormalAttachments {
|
||
|
data := make([]string, 0, 16)
|
||
|
data = append(data, "--"+boundary)
|
||
|
data = append(data, "Content-Type: multipart/alternative; boundary="+boundaryAlt)
|
||
|
data = append(data, "")
|
||
|
data = append(data, "--"+boundaryAlt)
|
||
|
data = append(data, "Content-Type: text/plain; charset=UTF-8")
|
||
|
data = append(data, "Content-Transfer-Encoding: 7bit")
|
||
|
data = append(data, "")
|
||
|
data = append(data, body.Plain)
|
||
|
data = append(data, "")
|
||
|
data = append(data, "--"+boundaryAlt)
|
||
|
data = append(data, "Content-Type: text/html; charset=UTF-8")
|
||
|
data = append(data, "Content-Transfer-Encoding: 7bit")
|
||
|
data = append(data, "")
|
||
|
data = append(data, body.HTML)
|
||
|
data = append(data, "")
|
||
|
data = append(data, "--"+boundaryAlt+"--")
|
||
|
return data
|
||
|
}
|
||
|
|
||
|
if body.HTML != "" && body.Plain != "" && hasInlineAttachments {
|
||
|
data := make([]string, 0, 2)
|
||
|
data = append(data, "--"+boundary)
|
||
|
data = append(data, body.HTML)
|
||
|
return data
|
||
|
}
|
||
|
|
||
|
if body.HTML != "" && body.Plain != "" {
|
||
|
data := make([]string, 0, 8)
|
||
|
data = append(data, "--"+boundary)
|
||
|
data = append(data, "Content-Type: text/plain; charset=UTF-8")
|
||
|
data = append(data, "Content-Transfer-Encoding: 7bit")
|
||
|
data = append(data, "")
|
||
|
data = append(data, body.Plain)
|
||
|
data = append(data, "")
|
||
|
data = append(data, "--"+boundary)
|
||
|
data = append(data, "Content-Type: text/html; charset=UTF-8")
|
||
|
data = append(data, "Content-Transfer-Encoding: 7bit")
|
||
|
data = append(data, "")
|
||
|
data = append(data, body.HTML)
|
||
|
return data
|
||
|
}
|
||
|
|
||
|
if body.HTML != "" {
|
||
|
data := make([]string, 0, 2)
|
||
|
data = append(data, "--"+boundary)
|
||
|
data = append(data, "Content-Type: text/html; charset=UTF-8")
|
||
|
data = append(data, "Content-Transfer-Encoding: 7bit")
|
||
|
data = append(data, "")
|
||
|
data = append(data, body.HTML)
|
||
|
return data
|
||
|
}
|
||
|
|
||
|
if body.Plain != "" {
|
||
|
data := make([]string, 0, 2)
|
||
|
data = append(data, "--"+boundary)
|
||
|
data = append(data, "Content-Type: text/plain; charset=UTF-8")
|
||
|
data = append(data, "Content-Transfer-Encoding: 7bit")
|
||
|
data = append(data, "")
|
||
|
data = append(data, body.Plain)
|
||
|
return data
|
||
|
}
|
||
|
|
||
|
data := make([]string, 0, 16)
|
||
|
data = append(data, "--"+boundary)
|
||
|
data = append(data, "Content-Type: text/plain; charset=UTF-8")
|
||
|
data = append(data, "Content-Transfer-Encoding: 7bit")
|
||
|
data = append(data, "")
|
||
|
data = append(data, "") // no content ?!?
|
||
|
return data
|
||
|
}
|