diff --git a/smtp/data.go b/smtp/data.go index c3f293b..7a59d75 100644 --- a/smtp/data.go +++ b/smtp/data.go @@ -40,8 +40,10 @@ func DataWrite(w io.Writer, r io.Reader) error { c := p[n] if c == '\n' { if firstcr < 0 { - // Bare newline. - return ErrCRLF + if n > 0 || last != '\r' { + // Bare newline. + return ErrCRLF + } } else if firstcr != n-1 { // Bare carriage return. return ErrCRLF diff --git a/smtp/data_test.go b/smtp/data_test.go index ac0496c..f438b08 100644 --- a/smtp/data_test.go +++ b/smtp/data_test.go @@ -129,3 +129,27 @@ func TestDataReader(t *testing.T) { t.Fatalf("got err %v, expected io.ErrUnexpectedEOF", err) } } + +func TestDataWriteLineBoundaries(t *testing.T) { + const valid = "Subject: test\r\n\r\nbody\r\n" + if err := DataWrite(io.Discard, &oneReader{[]byte(valid)}); err != nil { + t.Fatalf("data write: %v", err) + } +} + +// oneReader returns data one byte at a time. +type oneReader struct { + buf []byte +} + +func (r *oneReader) Read(buf []byte) (int, error) { + if len(r.buf) == 0 { + return 0, io.EOF + } + if len(buf) == 0 { + return 0, nil + } + buf[0] = r.buf[0] + r.buf = r.buf[1:] + return 1, nil +}