mirror of
https://git.sr.ht/~rjarry/aerc
synced 2026-03-02 18:23:33 +01:00
send: ensure crlf line endings
RFC 5322 states that messages should only use CRLF line endings. Here are two important excerpts: > 2.1. General Description > > Messages are divided into lines of characters. A line is a series of > characters that is delimited with the two characters carriage-return > and line-feed; that is, the carriage return (CR) character (ASCII > value 13) followed immediately by the line feed (LF) character (ASCII > value 10). (The carriage return/line feed pair is usually written in > this document as "CRLF".) > 2.3. Body > > The body of a message is simply lines of US-ASCII characters. The > only two limitations on the body are as follows: > > o CR and LF MUST only occur together as CRLF; they MUST NOT appear > independently in the body. > o Lines of characters in the body MUST be limited to 998 characters, > and SHOULD be limited to 78 characters, excluding the CRLF. Most MTA are tolerant to invalid messages but some others are more pedantic. Ensure we only send valid line endings. Link: https://www.rfc-editor.org/rfc/rfc5322.html#section-2.1 Link: https://www.rfc-editor.org/rfc/rfc5322.html#section-2.3 Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Matěj Cepl <mcepl@cepl.eu>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package send
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
@@ -23,14 +25,45 @@ func NewSender(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var w io.WriteCloser
|
||||
|
||||
switch protocol {
|
||||
case "smtp", "smtp+insecure", "smtps":
|
||||
return newSmtpSender(protocol, auth, uri, domain, from, rcpts)
|
||||
w, err = newSmtpSender(protocol, auth, uri, domain, from, rcpts)
|
||||
case "jmap":
|
||||
return newJmapSender(worker, from, rcpts, copyTo)
|
||||
w, err = newJmapSender(worker, from, rcpts, copyTo)
|
||||
case "":
|
||||
return newSendmailSender(uri, rcpts)
|
||||
w, err = newSendmailSender(uri, rcpts)
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported protocol %s", protocol)
|
||||
err = fmt.Errorf("unsupported protocol %s", protocol)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &crlfWriter{w: w}, nil
|
||||
}
|
||||
|
||||
type crlfWriter struct {
|
||||
w io.WriteCloser
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
func (w *crlfWriter) Write(p []byte) (int, error) {
|
||||
return w.buf.Write(p)
|
||||
}
|
||||
|
||||
func (w *crlfWriter) Close() error {
|
||||
defer w.w.Close() // ensure closed even on error
|
||||
|
||||
scan := bufio.NewScanner(&w.buf)
|
||||
for scan.Scan() {
|
||||
if _, err := w.w.Write(append(scan.Bytes(), '\r', '\n')); err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if scan.Err() != nil {
|
||||
return scan.Err()
|
||||
}
|
||||
|
||||
return w.w.Close()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user