package mailhtml import ( "regexp" "strings" "golang.org/x/net/html" "golang.org/x/net/html/atom" ) var ( styleOpen = regexp.MustCompile(`(?i)]`) docMarkers = regexp.MustCompile(`(?i)<(!doctype\s|html[\s>]|body[\s>]|head[\s>])`) ) // isFullDocument reports whether a body is a whole HTML document rather than // the fragment our own editor emits. The two are rendered back differently: // a fragment must not gain an wrapper it never had. func isFullDocument(body string) bool { return docMarkers.MatchString(body) } // IsFullDocument reports whether a body was authored as a complete HTML // document. Callers that wrap a body in their own shell (a preview frame) need // to know not to nest one document inside another. func IsFullDocument(body string) bool { return isFullDocument(body) } // InsertBeforeBodyEnd places a fragment at the end of the message body: just // inside for a full document, at the end otherwise. // // The closing tag is found by scanning rather than by searching for the // literal string, because HTML mail is full of Outlook conditional comments // () and a written inside one is not the // document's. Inserting there put the signature and the opt-out footer inside // a comment, where Outlook showed them and every other client did not. func InsertBeforeBodyEnd(body, fragment string) string { if fragment == "" { return body } if at := lastRealTag(body, "body"); at >= 0 { return body[:at] + fragment + body[at:] } if at := lastRealTag(body, "html"); at >= 0 { return body[:at] + fragment + body[at:] } return body + fragment } // lastRealTag returns the offset of the last closing tag with the given name // that is genuine markup, skipping any inside a comment,