Skip to content

Commit e784ad0

Browse files
committed
client: ensure dataCloser is only closed twice
Otherwise we end up writing the dot plus CRLF sequence multiple times.
1 parent 7c94d3c commit e784ad0

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

client.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,14 @@ type dataCloser struct {
430430
c *Client
431431
io.WriteCloser
432432
statusCb func(rcpt string, status *SMTPError)
433+
closed bool
433434
}
434435

435436
func (d *dataCloser) Close() error {
437+
if d.closed {
438+
return fmt.Errorf("smtp: data writer closed twice")
439+
}
440+
436441
if err := d.WriteCloser.Close(); err != nil {
437442
return err
438443
}
@@ -457,7 +462,6 @@ func (d *dataCloser) Close() error {
457462
}
458463
expectedResponses--
459464
}
460-
return nil
461465
} else {
462466
_, _, err := d.c.Text.ReadResponse(250)
463467
if err != nil {
@@ -466,8 +470,10 @@ func (d *dataCloser) Close() error {
466470
}
467471
return err
468472
}
469-
return nil
470473
}
474+
475+
d.closed = true
476+
return nil
471477
}
472478

473479
// Data issues a DATA command to the server and returns a writer that
@@ -481,7 +487,7 @@ func (c *Client) Data() (io.WriteCloser, error) {
481487
if err != nil {
482488
return nil, err
483489
}
484-
return &dataCloser{c, c.Text.DotWriter(), nil}, nil
490+
return &dataCloser{c: c, WriteCloser: c.Text.DotWriter()}, nil
485491
}
486492

487493
// LMTPData is the LMTP-specific version of the Data method. It accepts a callback
@@ -501,7 +507,7 @@ func (c *Client) LMTPData(statusCb func(rcpt string, status *SMTPError)) (io.Wri
501507
if err != nil {
502508
return nil, err
503509
}
504-
return &dataCloser{c, c.Text.DotWriter(), statusCb}, nil
510+
return &dataCloser{c: c, WriteCloser: c.Text.DotWriter(), statusCb: statusCb}, nil
505511
}
506512

507513
// SendMail will use an existing connection to send an email from

0 commit comments

Comments
 (0)