Merge pull request #38 from wneessen/37-attachment-length

Fixes bug with attachment encoding
This commit is contained in:
Winni Neessen 2022-08-14 12:13:07 +02:00 committed by GitHub
commit c6fe75f2d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 68 additions and 1 deletions

60
base64_writer.go Normal file
View file

@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
//
// SPDX-License-Identifier: MIT
package mail
import "io"
// Base64LineBreaker is a io.WriteCloser that writes Base64 encoded data streams
// with line breaks at a given line length
type Base64LineBreaker struct {
line [MaxBodyLength]byte
used int
out io.Writer
}
var nl = []byte(SingleNewLine)
// Write writes the data stream and inserts a SingleNewLine when the maximum
// line length is reached
func (l *Base64LineBreaker) Write(b []byte) (n int, err error) {
if l.used+len(b) < MaxBodyLength {
copy(l.line[l.used:], b)
l.used += len(b)
return len(b), nil
}
n, err = l.out.Write(l.line[0:l.used])
if err != nil {
return
}
excess := MaxBodyLength - l.used
l.used = 0
n, err = l.out.Write(b[0:excess])
if err != nil {
return
}
n, err = l.out.Write(nl)
if err != nil {
return
}
return l.Write(b[excess:])
}
// Close closes the Base64LineBreaker and writes any access data that is still
// unwritten in memory
func (l *Base64LineBreaker) Close() (err error) {
if l.used > 0 {
_, err = l.out.Write(l.line[0:l.used])
if err != nil {
return
}
_, err = l.out.Write(nl)
}
return
}

View file

@ -22,6 +22,10 @@ import (
// RFC 2047 suggests 76 characters // RFC 2047 suggests 76 characters
const MaxHeaderLength = 76 const MaxHeaderLength = 76
// MaxBodyLength defines the maximum line length for the mail body
// RFC 2047 suggests 76 characters
const MaxBodyLength = 76
// SingleNewLine represents a new line that can be used by the msgWriter to issue a carriage return // SingleNewLine represents a new line that can be used by the msgWriter to issue a carriage return
const SingleNewLine = "\r\n" const SingleNewLine = "\r\n"
@ -277,12 +281,14 @@ func (mw *msgWriter) writeBody(f func(io.Writer) (int64, error), e Encoding) {
w = mw.pw w = mw.pw
} }
wbuf := bytes.Buffer{} wbuf := bytes.Buffer{}
lb := Base64LineBreaker{}
lb.out = &wbuf
switch e { switch e {
case EncodingQP: case EncodingQP:
ew = quotedprintable.NewWriter(&wbuf) ew = quotedprintable.NewWriter(&wbuf)
case EncodingB64: case EncodingB64:
ew = base64.NewEncoder(base64.StdEncoding, &wbuf) ew = base64.NewEncoder(base64.StdEncoding, &lb)
case NoEncoding: case NoEncoding:
_, mw.err = f(&wbuf) _, mw.err = f(&wbuf)
n, mw.err = io.Copy(w, &wbuf) n, mw.err = io.Copy(w, &wbuf)
@ -296,6 +302,7 @@ func (mw *msgWriter) writeBody(f func(io.Writer) (int64, error), e Encoding) {
_, mw.err = f(ew) _, mw.err = f(ew)
mw.err = ew.Close() mw.err = ew.Close()
mw.err = lb.Close()
n, mw.err = io.Copy(w, &wbuf) n, mw.err = io.Copy(w, &wbuf)
// Since the part writer uses the WriteTo() method, we don't need to add the // Since the part writer uses the WriteTo() method, we don't need to add the