Billionmail/BillionMail · error

SMTP data: %w

Error message

SMTP data: %w

What it means

This error wraps a failure of net/smtp Client.Data(), which issues the SMTP DATA command. The server refused to enter data mode (usually a 4xx/5xx reply) after envelope sender and recipients were accepted. No message body was transmitted.

Source

Thrown at core/internal/service/mail_service/sending.go:429

	// Set the sender
	// MAIL FROM
	if err = e.client.Mail(e.Email); err != nil {
		return fmt.Errorf("SMTP mail: %w", err)
	}

	// Set the recipients
	// RCPT TO
	for _, to := range recipients {
		if err = e.client.Rcpt(to); err != nil {
			return fmt.Errorf("SMTP rcpt: %w", err)
		}
	}

	// Get a writer for the message body
	var w io.WriteCloser
	w, err = e.client.Data()
	if err != nil {
		return fmt.Errorf("SMTP data: %w", err)
	}

	// Write the message
	if _, err = w.Write(msg); err != nil {
		return fmt.Errorf("SMTP write: %w", err)
	}

	// Close the writer
	if err = w.Close(); err != nil {
		return fmt.Errorf("SMTP close writer: %w", err)
	}

	return nil
}

// isSecure check if TLS connection is needed
func (e *EmailSender) isSecure() bool {
	// usually,

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Check mail server logs for the reply code returned at DATA to identify policy rejection vs connection issue
  2. Retry with a fresh SMTP connection — the session may be stale; the deferred Reset() already attempts to clear state
  3. If a milter (rspamd) rejects at DATA, inspect milter settings and message headers triggering the rejection
  4. Ensure keepalives/short transaction times so the connection doesn't idle out between commands
Defensive patterns

Strategy: retry

Validate before calling

if sender == nil || !connectionHealthy() {
    return errors.New("SMTP session not ready for DATA")
}

Try / catch

err := sender.Send(msg, recipients)
if err != nil {
    if isTransient(err) { // 4xx or io.EOF
        backoffRetry(3)
    } else {
        logAndFail(err)
    }
}

Prevention

When it happens

Trigger: e.client.Data() returned an error — commonly a '554 transaction failed' reply, a connection that dropped after RCPT TO, or the server rejecting the transaction due to policy (spam filter, greylisting) between RCPT and DATA.

Common situations: Postfix smtpd bans or throttles the client after the envelope; connection idle-timed out mid-transaction; rspamd/milter rejects the transaction at DATA stage; network interruption during the SMTP session.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/7eb6d173e4638223. Report an issue: GitHub.