projectdiscovery/nuclei · error
invalid number of recipients: required 1, got %d
Error message
invalid number of recipients: required 1, got %d
What it means
Returned by smtp.Client.IsOpenRelay when the SMTPMessage does not have exactly one recipient: the check rejects len(msg.to) == 0 and len(msg.to) > 1 after the MAIL FROM command. The open-relay probe is intentionally minimal — one sender, one recipient — so the library enforces a single Rcpt call rather than guessing which recipient to test.
Source
Thrown at pkg/js/libs/smtp/smtp.go:156
}
addr := net.JoinHostPort(c.host, c.port)
conn, err := dialer.Fastdialer.Dial(c.nj.Context(), "tcp", addr)
if err != nil {
return false, err
}
defer func() {
_ = conn.Close()
}()
client, err := smtp.NewClient(conn, c.host)
if err != nil {
return false, err
}
if err := client.Mail(msg.from); err != nil {
return false, err
}
if len(msg.to) == 0 || len(msg.to) > 1 {
return false, fmt.Errorf("invalid number of recipients: required 1, got %d", len(msg.to))
}
if err := client.Rcpt(msg.to[0]); err != nil {
return false, err
}
// Send the email body.
wc, err := client.Data()
if err != nil {
return false, err
}
_, err = wc.Write([]byte(msg.String()))
if err != nil {
return false, err
}
err = wc.Close()
if err != nil {
return false, errView on GitHub (pinned to 265b3a3dec)
Solutions
- Set exactly one recipient on the message before IsOpenRelay
- Remove extra To/AddTo calls that inflate the recipient list
- If you built a multi-recipient message, construct a fresh single-recipient message for the relay probe
Example fix
// before
const msg = new smtp.SMTPMessage();
msg.From('attacker@evil.com');
msg.To('a@evil.com');
msg.To('b@evil.com');
client.IsOpenRelay(msg);
// after
const msg = new smtp.SMTPMessage();
msg.From('attacker@evil.com');
msg.To('a@evil.com');
client.IsOpenRelay(msg); Defensive patterns
Strategy: validation
Validate before calling
const msg = new smtp.SMTPMessage(); msg.From(fromAddr); msg.To(singleRecipient); // exactly one // do not call To/AddTo again before IsOpenRelay client.IsOpenRelay(msg);
Try / catch
try { client.IsOpenRelay(msg) } catch (e) { if (String(e).includes('invalid number of recipients')) { /* rebuild message with one recipient */ } else { throw e; } } Prevention
- Build a dedicated single-recipient message for relay probes
- Do not reuse multi-recipient compose helpers
- Set the recipient immediately after From to avoid omission
When it happens
Trigger: Calling IsOpenRelay with a message where To() was never called (zero recipients); adding multiple recipients (To called twice, or an AddTo-style API used repeatedly) before the probe; copying message-building code from a send-email flow that legitimately has several recipients.
Common situations: Template authors reusing mail-composition helpers that add default recipients; forgetting the To step entirely; assuming the library loops over recipients like a real MTA submit.
Related errors
- file path cannot be empty
- dialers not initialized for %s
- invalid host or port
- parse target: %w
- invalid host or port
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/11c6652e7206ed12.
Report an issue: GitHub.