void smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name, SMTP_RESP *resp, const char *format,...) { DELIVER_REQUEST *request = state->request; SMTP_SESSION *session = state->session; DSN_BUF *why = state->why; int status; int soft_error; int soft_bounce_error; va_list ap; /* * Sanity check. */ if (SMTP_RCPT_ISMARKED(rcpt)) msg_panic("smtp_rcpt_fail: recipient <%s> is marked", rcpt->address); /* * Initialize. */ va_start(ap, format); vsmtp_fill_dsn(state, mta_name, resp->dsn, resp->str, format, ap); va_end(ap); soft_error = STR(why->status)[0] == '4'; soft_bounce_error = (STR(why->status)[0] == '5' && var_soft_bounce); if (state->session && mta_name) smtp_check_code(state->session, resp->code); /* * Don't defer this recipient record just yet when this error qualifies * for trying other mail servers. Just log something informative to show * why we're skipping this recipient now. */ if ((soft_error || soft_bounce_error) && (state->misc_flags & SMTP_MISC_FLAG_FINAL_SERVER) == 0) { msg_info("%s: %s", request->queue_id, STR(why->reason)); SMTP_RCPT_KEEP(state, rcpt); } /* * Defer or bounce this recipient, and delete from the delivery request. * If the bounce fails, defer instead and do not qualify the recipient * for delivery to a backup server. * * Note: we may still make an SMTP connection to deliver other recipients * that did qualify for delivery to a backup server. */ else { (void) DSN_FROM_DSN_BUF(state->why); status = (soft_error ? defer_append : bounce_append) (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, session ? session->namaddrport : "none", &why->dsn); if (status == 0) deliver_completed(state->src, rcpt->offset); SMTP_RCPT_DROP(state, rcpt); state->status |= status; } }
void smtp_rcpt_done(SMTP_STATE *state, SMTP_RESP *resp, RECIPIENT *rcpt) { DELIVER_REQUEST *request = state->request; SMTP_SESSION *session = state->session; SMTP_ITERATOR *iter = state->iterator; DSN_BUF *why = state->why; const char *dsn_action = "relayed"; int status; /* * Assume this was intermediate delivery when the server announced DSN * support, and don't send a DSN "SUCCESS" notification. */ if (session->features & SMTP_FEATURE_DSN) rcpt->dsn_notify &= ~DSN_NOTIFY_SUCCESS; /* * Assume this was final delivery when the LMTP server announced no DSN * support. In backwards compatibility mode, send a "relayed" instead of * a "delivered" DSN "SUCCESS" notification. Do not attempt to "simplify" * the expression. The redundancy is for clarity. It is trivially * eliminated by the compiler. There is no need to sacrifice clarity for * the sake of "performance". */ if ((session->features & SMTP_FEATURE_DSN) == 0 && !smtp_mode && var_lmtp_assume_final != 0) dsn_action = "delivered"; /* * Report success and delete the recipient from the delivery request. * Defer if the success can't be reported. * * Note: the DSN action is ignored in case of address probes. */ dsb_update(why, resp->dsn, dsn_action, DSB_MTYPE_DNS, STR(iter->host), DSB_DTYPE_SMTP, resp->str, "%s", resp->str); status = sent(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, session->namaddrport, DSN_FROM_DSN_BUF(why)); if (status == 0) if (request->flags & DEL_REQ_FLAG_SUCCESS) deliver_completed(state->src, rcpt->offset); SMTP_RCPT_DROP(state, rcpt); state->status |= status; }
static int smtp_bulk_fail(SMTP_STATE *state, int throttle_queue) { DELIVER_REQUEST *request = state->request; SMTP_SESSION *session = state->session; DSN_BUF *why = state->why; RECIPIENT *rcpt; int status; int soft_error = (STR(why->status)[0] == '4'); int soft_bounce_error = (STR(why->status)[0] == '5' && var_soft_bounce); int nrcpt; /* * Don't defer the recipients just yet when this error qualifies them for * delivery to a backup server. Just log something informative to show * why we're skipping this host. */ if ((soft_error || soft_bounce_error) && (state->misc_flags & SMTP_MISC_FLAG_FINAL_SERVER) == 0) { msg_info("%s: %s", request->queue_id, STR(why->reason)); for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) { rcpt = request->rcpt_list.info + nrcpt; if (SMTP_RCPT_ISMARKED(rcpt)) continue; SMTP_RCPT_KEEP(state, rcpt); } } /* * Defer or bounce all the remaining recipients, and delete them from the * delivery request. If a bounce fails, defer instead and do not qualify * the recipient for delivery to a backup server. */ else { /* * If we are still in the connection set-up phase, update the set-up * completion time here, otherwise the time spent in set-up latency * will be attributed as message transfer latency. * * All remaining recipients have failed at this point, so we update the * delivery completion time stamp so that multiple recipient status * records show the same delay values. */ if (request->msg_stats.conn_setup_done.tv_sec == 0) { GETTIMEOFDAY(&request->msg_stats.conn_setup_done); request->msg_stats.deliver_done = request->msg_stats.conn_setup_done; } else GETTIMEOFDAY(&request->msg_stats.deliver_done); (void) DSN_FROM_DSN_BUF(why); for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) { rcpt = request->rcpt_list.info + nrcpt; if (SMTP_RCPT_ISMARKED(rcpt)) continue; status = (soft_error ? defer_append : bounce_append) (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id, &request->msg_stats, rcpt, session ? session->namaddrport : "none", &why->dsn); if (status == 0) deliver_completed(state->src, rcpt->offset); SMTP_RCPT_DROP(state, rcpt); state->status |= status; } if ((state->misc_flags & SMTP_MISC_FLAG_COMPLETE_SESSION) == 0 && throttle_queue && (soft_error || soft_bounce_error) && request->hop_status == 0) request->hop_status = DSN_COPY(&why->dsn); } /* * Don't cache this session. We can't talk to this server. */ if (throttle_queue && session) DONT_CACHE_BAD_SESSION; return (-1); }