jstedfast/MailKit · error · SmtpCommandException

MessageNotAccepted

MessageNotAccepted

Error message

No recipients were accepted.

What it means

During SendAsync, after RCPT TO is issued for each recipient, MailKit counts how many were accepted. If zero recipients were accepted by the server, it fires OnNoRecipientsAccepted and throws SmtpCommandException with SmtpStatusCode.TransactionFailed and this message, because the DATA/BDAT phase cannot proceed without at least one recipient.

Solutions

  1. Inspect the RCPT TO failures (SmtpClient.RecipientsAccepted / the per-recipient exceptions) to see why each was rejected.
  2. Verify the message has valid recipients in To/Cc/Bcc before sending.
  3. Ensure SMTP authentication succeeded and the account has relay rights.
  4. Handle the SmtpCommandException (code MessageNotAccepted) and check NoRecipientsAccepted event details.

Example fix

// before
await client.SendAsync(message); // message.To is empty
// after
if (!message.To.Any() && !message.Cc.Any() && !message.Bcc.Any())
    throw new InvalidOperationException("Message has no recipients");
await client.SendAsync(message);
Defensive patterns

Strategy: validation

Validate before calling

bool hasRecipients = message.To.Count + message.Cc.Count + message.Bcc.Count > 0;
if (!hasRecipients)
    throw new InvalidOperationException("Cannot send: message has no recipients");

Type guard

bool HasValidRecipients(MimeMessage m) => m != null && (m.To.Any(a => a is MailboxAddress mb && MailboxAddress.IsValid(mb.Address)) || m.Cc.Any() || m.Bcc.Any());

Try / catch

try {
    await client.SendAsync(message);
} catch (SmtpCommandException ex) when (ex.ErrorCode == SmtpErrorCode.MessageNotAccepted) {
    logger.LogWarning("All recipients rejected: {Message}", ex.Message);
    // inspect per-recipient failures / NoRecipientsAccepted event data before retrying
}

Prevention

When it happens

Trigger: Calling SendAsync when every RCPT TO was rejected - e.g. Message.To/Cc/Bcc all empty, all recipients invalid, relay denied, or server rejecting each address with a permanent error.

Common situations: Sending mail where the recipient list was filtered to empty beforehand; authenticated user lacks relay permission; domain not accepted by the server; anti-spam rejection of all recipients.

Related errors


AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15). Data as JSON: /api/errors/5a11a0bc74db7be7. Report an issue: GitHub.

Appendix: source

Thrown at MailKit/Net/Smtp/AsyncSmtpClient.cs:1015

					if (await RcptToAsync (format, message, recipients[i], pipeline, cancellationToken).ConfigureAwait (false))
						recipientsAccepted++;
				}

				if (queued.Count > 0) {
					// Note: if PIPELINING is supported, this will flush all outstanding
					// MAIL FROM and RCPT TO commands to the server and then process
					// all of their responses.
					var results = await FlushCommandQueueAsync (message, sender, recipients, cancellationToken).ConfigureAwait (false);

					recipientsAccepted = results.RecipientsAccepted;

					if (results.FirstException != null)
						throw results.FirstException;
				}

				if (recipientsAccepted == 0) {
					OnNoRecipientsAccepted (message);
					throw new SmtpCommandException (SmtpErrorCode.MessageNotAccepted, SmtpStatusCode.TransactionFailed, "No recipients were accepted.");
				}

				if (bdat)
					return await BdatAsync (format, message, size, cancellationToken, progress).ConfigureAwait (false);

				var dataResponse = await Stream.SendCommandAsync ("DATA\r\n", cancellationToken).ConfigureAwait (false);

				ParseDataResponse (dataResponse);

				return await MessageDataAsync (format, message, size, cancellationToken, progress).ConfigureAwait (false);
			} catch (ServiceNotAuthenticatedException ex) {
				operation.SetError (ex);

				// do not disconnect
				await ResetAsync (cancellationToken).ConfigureAwait (false);
				throw;
			} catch (SmtpCommandException ex) {
				operation.SetError (ex);

View on GitHub (pinned to 9d3859a785)