Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions eml.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ func parseEMLBodyParts(parsedMsg *netmail.Message, bodybuf *bytes.Buffer, msg *M
if value, ok := params["charset"]; ok {
msg.SetCharset(Charset(value))
}
if value, ok := params["boundary"]; ok {
msg.SetBoundary(value)
}

switch {
case strings.EqualFold(mediatype, TypeTextPlain.String()),
Expand Down
27 changes: 27 additions & 0 deletions eml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1231,3 +1231,30 @@ func TestEMLToMsgFromFile(t *testing.T) {
}
})
}

func TestToAndFromEMLMultipart(t *testing.T) {
t.Run("TestToAndFromEMLMultipart succeeds", func(t *testing.T) {
msg := NewMsg()
_ = msg.To("[email protected]")
_ = msg.FromFormat("Person", "[email protected]")
msg.Subject("Test Subject")

msg.SetBodyString(TypeTextPlain, "hi")
msg.AddAlternativeString(TypeTextHTML, "<h1>hi</h1>")

var emlBuf bytes.Buffer
_, _ = msg.WriteTo(&emlBuf)

decMsg, _ := EMLToMsgFromReader(&emlBuf)

var resBuf bytes.Buffer
_, _ = decMsg.WriteTo(&resBuf)

str := resBuf.String()

contentTypeCount := strings.Count(str, "Content-Type: multipart/alternative")
if contentTypeCount != 1 {
t.Fatalf("TestToAndFromEMLMultipart failed: want 1 multipart/alternative Content-Type header, got %d", contentTypeCount)
}
})
}
29 changes: 17 additions & 12 deletions msgwriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,28 +137,28 @@ func (mw *msgWriter) writeMsg(msg *Msg) {
mw.err = err
return
}
mw.startMP(MIMESMIMESigned, boundary)
mw.startMP(msg, MIMESMIMESigned, boundary)
mw.writeString(DoubleNewLine)
}
if msg.hasMixed() {
boundary := mw.getMultipartBoundary(msg, MIMEMixed)
boundary = mw.startMP(MIMEMixed, boundary)
boundary = mw.startMP(msg, MIMEMixed, boundary)
msg.multiPartBoundary[MIMEMixed] = boundary
if mw.depth == 1 {
mw.writeString(DoubleNewLine)
}
}
if msg.hasRelated() {
boundary := mw.getMultipartBoundary(msg, MIMERelated)
boundary = mw.startMP(MIMERelated, boundary)
boundary = mw.startMP(msg, MIMERelated, boundary)
msg.multiPartBoundary[MIMERelated] = boundary
if mw.depth == 1 {
mw.writeString(DoubleNewLine)
}
}
if msg.hasAlt() {
boundary := mw.getMultipartBoundary(msg, MIMEAlternative)
boundary = mw.startMP(MIMEAlternative, boundary)
boundary = mw.startMP(msg, MIMEAlternative, boundary)
msg.multiPartBoundary[MIMEAlternative] = boundary
if mw.depth == 1 {
mw.writeString(DoubleNewLine)
Expand All @@ -167,10 +167,10 @@ func (mw *msgWriter) writeMsg(msg *Msg) {
if msg.hasPGPType() {
switch msg.pgptype {
case PGPEncrypt:
mw.startMP(`encrypted; protocol="application/pgp-encrypted"`,
mw.startMP(msg, `encrypted; protocol="application/pgp-encrypted"`,
msg.boundary)
case PGPSignature:
mw.startMP(`signed; protocol="application/pgp-signature";`,
mw.startMP(msg, `signed; protocol="application/pgp-signature";`,
msg.boundary)
default:
}
Expand Down Expand Up @@ -251,6 +251,7 @@ func (mw *msgWriter) writePreformattedGenHeader(msg *Msg) {
// generated. It also handles writing a new part when nested multipart structures are used.
//
// Parameters:
// - msg: The message whose multipart headers are being written.
// - mimeType: The MIME type of the multipart content (e.g., "mixed", "alternative").
// - boundary: The boundary string separating different parts of the multipart message.
//
Expand All @@ -259,7 +260,7 @@ func (mw *msgWriter) writePreformattedGenHeader(msg *Msg) {
//
// References:
// - https://datatracker.ietf.org/doc/html/rfc2046
func (mw *msgWriter) startMP(mimeType MIMEType, boundary string) string {
func (mw *msgWriter) startMP(msg *Msg, mimeType MIMEType, boundary string) string {
multiPartWriter := multipart.NewWriter(mw)
if boundary != "" {
mw.err = multiPartWriter.SetBoundary(boundary)
Expand All @@ -269,12 +270,16 @@ func (mw *msgWriter) startMP(mimeType MIMEType, boundary string) string {
multiPartWriter.Boundary())
mw.multiPartWriter[mw.depth] = multiPartWriter

if mw.depth == 0 {
mw.writeString(fmt.Sprintf("%s: %s", HeaderContentType, contentType))
}
if mw.depth > 0 {
mw.newPart(map[string][]string{"Content-Type": {contentType}})
// Do not write Content-Type if the header was already written as part of genHeaders.
if _, ok := msg.genHeader[HeaderContentType]; !ok {
if mw.depth == 0 {
mw.writeString(fmt.Sprintf("%s: %s", HeaderContentType, contentType))
}
if mw.depth > 0 {
mw.newPart(map[string][]string{"Content-Type": {contentType}})
}
}

mw.depth++
return multiPartWriter.Boundary()
}
Expand Down
Loading