20141227 Feature: smtp_address_verify_target (default: rcpt) that determines what protocol stage decides if a recipient is valid. Specify "data" for servers that reject recipients after the DATA command. Files: mantools/postlink, proto/postconf.proto, global/mail_params.h, smtp/lmtp_params.c, smtp/smtp.c, smtp/smtp.h, smtp/smtp_params.c, smtp/smtp_proto.c. diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/man/man5/postconf.5 ./man/man5/postconf.5 --- /var/tmp/postfix-2.10.5/man/man5/postconf.5 2013-06-13 10:06:06.000000000 -0400 +++ ./man/man5/postconf.5 2014-12-28 12:34:49.000000000 -0500 @@ -2241,6 +2241,11 @@ configuration parameter. See there for details. .PP This feature is available in Postfix 2.8 and later. +.SH lmtp_address_verify_target (default: rcpt) +The LMTP-specific version of the smtp_address_verify_target +configuration parameter. See there for details. +.PP +This feature is available in Postfix 2.12 and later. .SH lmtp_assume_final (default: no) When a remote LMTP server announces no DSN support, assume that the @@ -5608,6 +5613,13 @@ .br .PP This feature is available in Postfix 2.8 and later. +.SH smtp_address_verify_target (default: rcpt) +In the context of email address verification, the SMTP protocol +stage that determines whether an email address is deliverable. +Specify one of "rcpt" or "data". The latter is needed with remote +SMTP servers that reject recipients after the DATA command. +.PP +This feature is available in Postfix 2.12 and later. .SH smtp_always_send_ehlo (default: yes) Always send EHLO at the start of an SMTP session. .PP diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/man/man8/smtp.8 ./man/man8/smtp.8 --- /var/tmp/postfix-2.10.5/man/man8/smtp.8 2012-07-17 15:40:55.000000000 -0400 +++ ./man/man8/smtp.8 2014-12-28 12:11:28.000000000 -0500 @@ -219,8 +219,9 @@ .PP Available in Postfix version 2.2.9 and later: .IP "\fBsmtp_cname_overrides_servername (version dependent)\fR" -Allow DNS CNAME records to override the servername that the -Postfix SMTP client uses for logging, SASL password lookup, TLS +When the remote SMTP servername is a DNS CNAME, replace the +servername with the result from CNAME expansion for the purpose of +logging, SASL password lookup, TLS policy decisions, or TLS certificate verification. .PP Available in Postfix version 2.3 and later: @@ -683,6 +684,11 @@ .IP "\fBsmtp_fallback_relay ($fallback_relay)\fR" Optional list of relay hosts for SMTP destinations that can't be found or that are unreachable. +.PP +Available with Postfix 2.12 and later: +.IP "\fBsmtp_address_verify_target (rcpt)\fR" +In the context of email address verification, the SMTP protocol +stage that determines whether an email address is deliverable. .SH "SEE ALSO" .na .nf diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/mantools/postlink ./mantools/postlink --- /var/tmp/postfix-2.10.5/mantools/postlink 2013-02-03 13:22:21.000000000 -0500 +++ ./mantools/postlink 2014-12-28 12:11:28.000000000 -0500 @@ -89,6 +89,8 @@ s;\baddress_verify_service_name\b;$&;g; s;\baddress_verify_transport_maps\b;$&;g; s;\baddress_verify_virtual_transport\b;$&;g; + s;\bsmtp_address_verify_target\b;$&;g; + s;\blmtp_address_verify_target\b;$&;g; s;\balias_database\b;$&;g; s;\balias_maps\b;$&;g; s;\ballow_mail_to_commands\b;$&;g; diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/proto/postconf.proto ./proto/postconf.proto --- /var/tmp/postfix-2.10.5/proto/postconf.proto 2013-06-13 09:48:55.000000000 -0400 +++ ./proto/postconf.proto 2014-12-28 12:34:23.000000000 -0500 @@ -14875,6 +14875,23 @@

This feature is available in Postfix 2.9 and later.

+%PARAM smtp_address_verify_target rcpt + +

In the context of email address verification, the SMTP protocol +stage that determines whether an email address is deliverable. +Specify one of "rcpt" or "data". The latter is needed with remote +SMTP servers that reject recipients after the DATA command. +

+ +

This feature is available in Postfix 2.12 and later.

+ +%PARAM lmtp_address_verify_target rcpt + +

The LMTP-specific version of the smtp_address_verify_target +configuration parameter. See there for details.

+ +

This feature is available in Postfix 2.12 and later.

+ %PARAM daemon_table_open_error_is_fatal no

How a Postfix daemon process handles errors while opening lookup diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/src/global/mail_params.h ./src/global/mail_params.h --- /var/tmp/postfix-2.10.5/src/global/mail_params.h 2013-06-22 19:57:19.000000000 -0400 +++ ./src/global/mail_params.h 2014-12-28 12:11:28.000000000 -0500 @@ -2688,6 +2688,14 @@ #define DEF_VRFY_XPORT_MAPS "$" VAR_TRANSPORT_MAPS extern char *var_vrfy_xport_maps; +#define SMTP_VRFY_TGT_RCPT "rcpt" +#define SMTP_VRFY_TGT_DATA "data" +#define VAR_LMTP_VRFY_TGT "lmtp_address_verify_target" +#define DEF_LMTP_VRFY_TGT SMTP_VRFY_TGT_RCPT +#define VAR_SMTP_VRFY_TGT "smtp_address_verify_target" +#define DEF_SMTP_VRFY_TGT SMTP_VRFY_TGT_RCPT +extern char *var_smtp_vrfy_tgt; + /* * Message delivery trace service. */ diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/src/smtp/lmtp_params.c ./src/smtp/lmtp_params.c --- /var/tmp/postfix-2.10.5/src/smtp/lmtp_params.c 2011-12-05 16:03:07.000000000 -0500 +++ ./src/smtp/lmtp_params.c 2014-12-28 12:11:28.000000000 -0500 @@ -32,6 +32,7 @@ VAR_LMTP_SASL_TYPE, DEF_LMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0, VAR_LMTP_BIND_ADDR, DEF_LMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0, VAR_LMTP_BIND_ADDR6, DEF_LMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0, + VAR_LMTP_VRFY_TGT, DEF_LMTP_VRFY_TGT, &var_smtp_vrfy_tgt, 1, 0, VAR_LMTP_HELO_NAME, DEF_LMTP_HELO_NAME, &var_smtp_helo_name, 1, 0, VAR_LMTP_HOST_LOOKUP, DEF_LMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0, VAR_LMTP_CACHE_DEST, DEF_LMTP_CACHE_DEST, &var_smtp_cache_dest, 0, 0, diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/src/smtp/smtp.c ./src/smtp/smtp.c --- /var/tmp/postfix-2.10.5/src/smtp/smtp.c 2012-07-17 15:40:55.000000000 -0400 +++ ./src/smtp/smtp.c 2014-12-28 12:11:28.000000000 -0500 @@ -197,8 +197,9 @@ /* .PP /* Available in Postfix version 2.2.9 and later: /* .IP "\fBsmtp_cname_overrides_servername (version dependent)\fR" -/* Allow DNS CNAME records to override the servername that the -/* Postfix SMTP client uses for logging, SASL password lookup, TLS +/* When the remote SMTP servername is a DNS CNAME, replace the +/* servername with the result from CNAME expansion for the purpose of +/* logging, SASL password lookup, TLS /* policy decisions, or TLS certificate verification. /* .PP /* Available in Postfix version 2.3 and later: @@ -645,6 +646,11 @@ /* .IP "\fBsmtp_fallback_relay ($fallback_relay)\fR" /* Optional list of relay hosts for SMTP destinations that can't be /* found or that are unreachable. +/* .PP +/* Available with Postfix 2.12 and later: +/* .IP "\fBsmtp_address_verify_target (rcpt)\fR" +/* In the context of email address verification, the SMTP protocol +/* stage that determines whether an email address is deliverable. /* SEE ALSO /* generic(5), output address rewriting /* header_checks(5), message header content inspection @@ -776,6 +782,7 @@ char *var_smtp_sasl_type; char *var_smtp_bind_addr; char *var_smtp_bind_addr6; +char *var_smtp_vrfy_tgt; bool var_smtp_rand_addr; int var_smtp_pix_thresh; int var_smtp_pix_delay; @@ -1005,6 +1012,11 @@ */ smtp_dns_res_opt = name_mask(VAR_SMTP_DNS_RES_OPT, dns_res_opt_masks, var_smtp_dns_res_opt); + + /* + * Address verification. + */ + smtp_vrfy_init(); } /* pre_init - pre-jail initialization */ diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/src/smtp/smtp.h ./src/smtp/smtp.h --- /var/tmp/postfix-2.10.5/src/smtp/smtp.h 2010-08-27 20:03:15.000000000 -0400 +++ ./src/smtp/smtp.h 2014-12-28 12:11:28.000000000 -0500 @@ -269,6 +269,7 @@ /* * smtp_proto.c */ +extern void smtp_vrfy_init(void); extern int smtp_helo(SMTP_STATE *); extern int smtp_xfer(SMTP_STATE *); extern int smtp_rset(SMTP_STATE *); @@ -386,6 +387,11 @@ #define DSN_BY_LOCAL_MTA ((char *) 0) /* DSN issued by local MTA */ +#define SMTP_RESP_SET_DSN(resp, _dsn) do { \ + vstring_strcpy((resp)->dsn_buf, (_dsn)); \ + (resp)->dsn = STR((resp)->dsn_buf); \ + } while (0) + /* * These operations implement a redundant mark-and-sweep algorithm that * explicitly accounts for the fate of every recipient. The interface is diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/src/smtp/smtp_params.c ./src/smtp/smtp_params.c --- /var/tmp/postfix-2.10.5/src/smtp/smtp_params.c 2011-12-05 16:03:07.000000000 -0500 +++ ./src/smtp/smtp_params.c 2014-12-28 12:11:28.000000000 -0500 @@ -33,6 +33,7 @@ VAR_SMTP_SASL_TYPE, DEF_SMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0, VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0, VAR_SMTP_BIND_ADDR6, DEF_SMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0, + VAR_SMTP_VRFY_TGT, DEF_SMTP_VRFY_TGT, &var_smtp_vrfy_tgt, 1, 0, VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0, VAR_SMTP_HOST_LOOKUP, DEF_SMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 0, VAR_SMTP_CACHE_DEST, DEF_SMTP_CACHE_DEST, &var_smtp_cache_dest, 0, 0, diff -ur --exclude=html --exclude=README_FILES /var/tmp/postfix-2.10.5/src/smtp/smtp_proto.c ./src/smtp/smtp_proto.c --- /var/tmp/postfix-2.10.5/src/smtp/smtp_proto.c 2012-01-14 19:41:15.000000000 -0500 +++ ./src/smtp/smtp_proto.c 2014-12-28 12:11:28.000000000 -0500 @@ -250,6 +250,24 @@ smtp_text_out, }; +static int smtp_vrfy_tgt; + +/* smtp_vrfy_init - initialize */ + +void smtp_vrfy_init(void) +{ + static const NAME_CODE vrfy_init_table[] = { + SMTP_VRFY_TGT_RCPT, SMTP_STATE_RCPT, + SMTP_VRFY_TGT_DATA, SMTP_STATE_DATA, + 0, + }; + + if ((smtp_vrfy_tgt = name_code(vrfy_init_table, NAME_CODE_FLAG_NONE, + var_smtp_vrfy_tgt)) == 0) + msg_fatal("bad protocol stage: \"%s = %s\"", + VAR_SMTP_VRFY_TGT, var_smtp_vrfy_tgt); +} + /* smtp_helo - perform initial handshake with SMTP server */ int smtp_helo(SMTP_STATE *state) @@ -1437,7 +1455,8 @@ dsn_notify_str(rcpt->dsn_notify)); } if ((next_rcpt = send_rcpt + 1) == SMTP_RCPT_LEFT(state)) - next_state = DEL_REQ_TRACE_ONLY(request->flags) ? + next_state = (DEL_REQ_TRACE_ONLY(request->flags) + && smtp_vrfy_tgt == SMTP_STATE_RCPT) ? SMTP_STATE_ABORT : SMTP_STATE_DATA; break; @@ -1704,7 +1723,8 @@ } ++nrcpt; /* If trace-only, mark the recipient done. */ - if (DEL_REQ_TRACE_ONLY(request->flags)) { + if (DEL_REQ_TRACE_ONLY(request->flags) + && smtp_vrfy_tgt == SMTP_STATE_RCPT) { translit(resp->str, "\n", " "); smtp_rcpt_done(state, resp, rcpt); } @@ -1718,7 +1738,8 @@ } /* If trace-only, send RSET instead of DATA. */ if (++recv_rcpt == SMTP_RCPT_LEFT(state)) - recv_state = DEL_REQ_TRACE_ONLY(request->flags) ? + recv_state = (DEL_REQ_TRACE_ONLY(request->flags) + && smtp_vrfy_tgt == SMTP_STATE_RCPT) ? SMTP_STATE_ABORT : SMTP_STATE_DATA; /* XXX Also: record if non-delivering session. */ break; @@ -1729,6 +1750,7 @@ * receiver can apply a course correction. */ case SMTP_STATE_DATA: + recv_state = SMTP_STATE_DOT; if (resp->code / 100 != 3) { if (nrcpt > 0) smtp_mesg_fail(state, session->host, resp, @@ -1738,7 +1760,30 @@ xfer_request[SMTP_STATE_DATA]); nrcpt = -1; } - recv_state = SMTP_STATE_DOT; + + /* + * In the case of a successful address probe with target + * equal to DATA, the remote server is now in the DATA + * state, and therefore we must not make any further + * attempt to send or receive on this connection. This + * means that we cannot not reuse the general-purpose + * course-correction logic below which sends RSET (and + * perhaps QUIT). Instead we "jump" straight to the exit + * and force an unceremonious disconnect. + */ + else if (DEL_REQ_TRACE_ONLY(request->flags) + && smtp_vrfy_tgt == SMTP_STATE_DATA) { + for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) { + rcpt = request->rcpt_list.info + nrcpt; + if (!SMTP_RCPT_ISMARKED(rcpt)) { + translit(resp->str, "\n", " "); + SMTP_RESP_SET_DSN(resp, "2.0.0"); + smtp_rcpt_done(state, resp, rcpt); + } + } + DONT_CACHE_THIS_SESSION; + send_state = recv_state = SMTP_STATE_LAST; + } break; /*