Skip to content

Commit

Permalink
if Attachment.HTMLRelated is set, mark attachment as inline (#135)
Browse files Browse the repository at this point in the history
Properly setting "Content-Disposition: inline" for attachments marked as
related. Otherwise some email clients (e.g. Thunderbird) are not showing
inline images correctly.
  • Loading branch information
bosim committed Dec 29, 2020
1 parent 127602e commit b84218f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 13 deletions.
40 changes: 29 additions & 11 deletions email.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,18 +276,11 @@ func (e *Email) Attach(r io.Reader, filename string, c string) (a *Attachment, e
return
}
at := &Attachment{
Filename: filename,
Header: textproto.MIMEHeader{},
Content: buffer.Bytes(),
Filename: filename,
ContentType: c,
Header: textproto.MIMEHeader{},
Content: buffer.Bytes(),
}
if c != "" {
at.Header.Set("Content-Type", c)
} else {
at.Header.Set("Content-Type", "application/octet-stream")
}
at.Header.Set("Content-Disposition", fmt.Sprintf("attachment;\r\n filename=\"%s\"", filename))
at.Header.Set("Content-ID", fmt.Sprintf("<%s>", filename))
at.Header.Set("Content-Transfer-Encoding", "base64")
e.Attachments = append(e.Attachments, at)
return at, nil
}
Expand Down Expand Up @@ -482,6 +475,7 @@ func (e *Email) Bytes() ([]byte, error) {
}
if len(htmlAttachments) > 0 {
for _, a := range htmlAttachments {
a.setDefaultHeaders()
ap, err := relatedWriter.CreatePart(a.Header)
if err != nil {
return nil, err
Expand All @@ -503,6 +497,7 @@ func (e *Email) Bytes() ([]byte, error) {
}
// Create attachment part, if necessary
for _, a := range otherAttachments {
a.setDefaultHeaders()
ap, err := w.CreatePart(a.Header)
if err != nil {
return nil, err
Expand Down Expand Up @@ -714,11 +709,34 @@ func (e *Email) SendWithStartTLS(addr string, a smtp.Auth, t *tls.Config) error
// Based on the mime/multipart.FileHeader struct, Attachment contains the name, MIMEHeader, and content of the attachment in question
type Attachment struct {
Filename string
ContentType string
Header textproto.MIMEHeader
Content []byte
HTMLRelated bool
}

func (at *Attachment) setDefaultHeaders() {
contentType := "application/octet-stream"
if len(at.ContentType) > 0 {
contentType = at.ContentType
}
at.Header.Set("Content-Type", contentType)

if len(at.Header.Get("Content-Disposition")) == 0 {
disposition := "attachment"
if at.HTMLRelated {
disposition = "inline"
}
at.Header.Set("Content-Disposition", fmt.Sprintf("%s;\r\n filename=\"%s\"", disposition, at.Filename))
}
if len(at.Header.Get("Content-ID")) == 0 {
at.Header.Set("Content-ID", fmt.Sprintf("<%s>", at.Filename))
}
if len(at.Header.Get("Content-Transfer-Encoding")) == 0 {
at.Header.Set("Content-Transfer-Encoding", "base64")
}
}

// base64Wrap encodes the attachment content, and wraps it according to RFC 2045 standards (every 76 chars)
// The output is then written to the specified io.Writer
func base64Wrap(w io.Writer, b []byte) {
Expand Down
9 changes: 7 additions & 2 deletions email_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,9 @@ func TestEmailWithHTMLAttachments(t *testing.T) {
}
for _, part := range ps {
// part has "header" and "body []byte"
cd := part.header.Get("Content-Disposition")
ct := part.header.Get("Content-Type")
if strings.Contains(ct, "image/png") {
if strings.Contains(ct, "image/png") && strings.HasPrefix(cd, "inline") {
imageFound = true
}
if strings.Contains(ct, "text/html") {
Expand Down Expand Up @@ -371,11 +372,15 @@ func TestEmailAttachment(t *testing.T) {
mixed := multipart.NewReader(msg.Body, params["boundary"])

// Check attachments.
_, err = mixed.NextPart()
a, err := mixed.NextPart()
if err != nil {
t.Fatalf("Could not find attachment component of email: %s", err)
}

if !strings.HasPrefix(a.Header.Get("Content-Disposition"), "attachment") {
t.Fatalf("Content disposition is not attachment: %s", a.Header.Get("Content-Disposition"))
}

if _, err = mixed.NextPart(); err != io.EOF {
t.Error("Expected only one attachment!")
}
Expand Down

0 comments on commit b84218f

Please sign in to comment.