Skip to content
Permalink
Browse files

Multiple 'RCPT TO': Add new option + logic to skip invalid recipients.

  • Loading branch information
volpav committed Jan 14, 2020
1 parent 875314e commit 74a4bb1fa90811ddf8d0081829bbd925a3cbfb53
@@ -0,0 +1,11 @@
Long: mail-rcpt-ignore-invalid
Help: Ignore invalid "RCPT TO" addresses during SMTP conversation
Protocols: SMTP
Added: 7.70.0
---
When sending data to multiple recipients, by default curl will abort and return
failure if one of the recipients indicate failure (on the "RCPT TO" command).

The default behavior can be changed by passing --mail-rcpt-ignore-invalid=1
command-line option which will make curl ignore invalid recipients and proceed
with SMTP session normally.
@@ -357,6 +357,8 @@ Address of the sender. See \fICURLOPT_MAIL_FROM(3)\fP
Address of the recipients. See \fICURLOPT_MAIL_RCPT(3)\fP
.IP CURLOPT_MAIL_AUTH
Authentication address. See \fICURLOPT_MAIL_AUTH(3)\fP
.IP CURLOPT_MAIL_RCPT_IGNORE_INVALID
Ignore invalid recipient addresses during SMTP conversation. See \fICURLOPT_MAIL_RCPT_IGNORE_INVALID(3)\fP
.SH TFTP OPTIONS
.IP CURLOPT_TFTP_BLKSIZE
TFTP block size. See \fICURLOPT_TFTP_BLKSIZE(3)\fP
@@ -0,0 +1,68 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
.\" *
.\" * This software is licensed as described in the file COPYING, which
.\" * you should have received as part of this distribution. The terms
.\" * are also available at https://curl.haxx.se/docs/copyright.html.
.\" *
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
.\" * copies of the Software, and permit persons to whom the Software is
.\" * furnished to do so, under the terms of the COPYING file.
.\" *
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
.\" * KIND, either express or implied.
.\" *
.\" **************************************************************************
.\"
.TH CURLOPT_MAIL_RCPT_IGNORE_INVALID 3 "16 Jan 2020" "libcurl 7.70.0" "curl_easy_setopt options"
.SH NAME
CURLOPT_MAIL_RCPT_IGNORE_INVALID \- ignore invalid recipient addresses during SMTP conversation
.SH SYNOPSIS
.nf
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAIL_RCPT_IGNORE_INVALID,
long ignore);
.SH DESCRIPTION
If \fIignore\fP is set to 1L, ignore the invalid recipients addresses during
SMTP conversation.

When sending data to multiple recipients, by default curl will abort and return
failure if one of the recipients indicate failure (on the "RCPT TO" command).

The default behavior can be changed by setting \fIignore\fP to 1L which will
make curl ignore invalid recipients and proceed with SMTP session normally.
.SH DEFAULT
0
.SH PROTOCOLS
SMTP
.SH EXAMPLE
.nf
CURL *curl = curl_easy_init();
if(curl) {
struct curl_slist *list;

/* Adding one valid and one invalid email addresses */
list = curl_slist_append(NULL, "person@example.com");
list = curl_slist_append(list, "invalidemailaddress");

curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT_IGNORE_INVALID, 1L);

ret = curl_easy_perform(curl);
curl_slist_free_all(list);
curl_easy_cleanup(curl);
}
.fi
.SH AVAILABILITY
Added in 7.70.0. Support for FTP added in 7.46.0.
.SH RETURN VALUE
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
.SH "SEE ALSO"
.BR CURLOPT_MAIL_FROM "(3), " CURLOPT_MAIL_RCPT "(3), "
@@ -188,6 +188,7 @@ man_MANS = \
CURLOPT_MAIL_AUTH.3 \
CURLOPT_MAIL_FROM.3 \
CURLOPT_MAIL_RCPT.3 \
CURLOPT_MAIL_RCPT_IGNORE_INVALID.3 \
CURLOPT_MAXAGE_CONN.3 \
CURLOPT_MAXCONNECTS.3 \
CURLOPT_MAXFILESIZE.3 \
@@ -469,6 +469,7 @@ CURLOPT_LOW_SPEED_TIME 7.1
CURLOPT_MAIL_AUTH 7.25.0
CURLOPT_MAIL_FROM 7.20.0
CURLOPT_MAIL_RCPT 7.20.0
CURLOPT_MAIL_RCPT_IGNORE_INVALID 7.70.0
CURLOPT_MAXAGE_CONN 7.65.0
CURLOPT_MAXCONNECTS 7.7
CURLOPT_MAXFILESIZE 7.10.8
@@ -1936,6 +1936,9 @@ typedef enum {
/* SASL authorisation identity */
CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289),

/* ignore invalid recipient addresses during SMTP conversation */
CURLOPT(CURLOPT_MAIL_RCPT_IGNORE_INVALID, CURLOPTTYPE_LONG, 290),

CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

@@ -2391,6 +2391,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* Set the list of mail recipients */
data->set.mail_rcpt = va_arg(param, struct curl_slist *);
break;
case CURLOPT_MAIL_RCPT_IGNORE_INVALID:
/* Ignore invalid recipient addresses during SMTP conversation */
data->set.mail_rcpt_ignore_invalid =
(0 != va_arg(param, long)) ? TRUE : FALSE;
break;
#endif

case CURLOPT_SASL_AUTHZID:
@@ -2480,13 +2485,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* for generic server options, the application will need to set this.
*/
result = Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
va_arg(param, char *));
break;
recipientsar *));
brerecipients

case CURLOPT_RTSP_TRANSPORT:
case recipients
/*
* The content of the Transport: header for the RTSP request
*/
* recipientsfor the RTSP request
*/recipients
result = Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
va_arg(param, char *));
break;
@@ -918,22 +918,38 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,

(void)instate; /* no use for this yet */

if(smtpcode/100 != 2) {
failf(data, "RCPT failed: %d", smtpcode);
result = CURLE_SEND_ERROR;
bool is_smtp_err = smtpcode/100 != 2;
bool is_smtp_blocking_err = is_smtp_err && !data->mail_rcpt_ignore_invalid;

if (is_smtp_err) {
smtp->rcpt_last_error = smtpcode;

if (is_smtp_blocking_err) {
failf(data, "RCPT failed: %d", smtpcode);
result = CURLE_SEND_ERROR;
}
} else {
smtp->rcpt_had_ok = TRUE;
}
else {

if (!is_smtp_blocking_err) {
smtp->rcpt = smtp->rcpt->next;

if(smtp->rcpt)
/* Send the next RCPT TO command */
result = smtp_perform_rcpt_to(conn);
else {
/* Send the DATA command */
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
if (!smtp->rcpt_had_ok) {
failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error);
result = CURLE_SEND_ERROR;
}
else {
/* Send the DATA command */
result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");

if(!result)
state(conn, SMTP_DATA);
if(!result)
state(conn, SMTP_DATA);
}
}
}

@@ -1287,6 +1303,12 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
/* Store the first recipient (or NULL if not specified) */
smtp->rcpt = data->set.mail_rcpt;

/* Keep track of whether we've successfully sent at least one "RCPT TO" */
smtp->rcpt_had_ok = FALSE;

/* Keep track of the last error we've received by sending "RCPT TO" */
smtp->rcpt_last_error = 0;

/* Initial data character is the first character in line: it is implicitly
preceded by a virtual CRLF. */
smtp->trailing_crlf = TRUE;
@@ -55,6 +55,9 @@ struct SMTP {
curl_pp_transfer transfer;
char *custom; /* Custom Request */
struct curl_slist *rcpt; /* Recipient list */
bool rcpt_had_ok; /* Whether any of the "RCPT TO" commands (depends on
a total number of recipients) succeeded so far */
int rcpt_last_error; /* The last error received for "RCPT TO" command */
size_t eob; /* Number of bytes of the EOB (End Of Body) that
have been received so far */
bool trailing_crlf; /* Specifies if the tailing CRLF is present */
@@ -1792,6 +1792,8 @@ struct UserDefined {
BIT(doh); /* DNS-over-HTTPS enabled */
BIT(doh_get); /* use GET for DoH requests, instead of POST */
BIT(http09_allowed); /* allow HTTP/0.9 responses */
BIT(mail_rcpt_ignore_invalid); /* ignore invalid recipient addresses during
SMTP conversation */
};

struct Names {
@@ -108,6 +108,7 @@ struct OperationConfig {
char *mail_from;
struct curl_slist *mail_rcpt;
char *mail_auth;
bool mail_rcpt_ignore_invalid; /* --mail-rcpt-ignore-invalid */
char *sasl_authzid; /* Authorisation identity (identity to use) */
bool sasl_ir; /* Enable/disable SASL initial response */
bool proxytunnel;
@@ -273,6 +273,7 @@ static const struct LongShort aliases[]= {
{"f", "fail", ARG_BOOL},
{"fa", "fail-early", ARG_BOOL},
{"fb", "styled-output", ARG_BOOL},
{"fc", "mail-rcpt-ignore-invalid", ARG_BOOL},
{"F", "form", ARG_STRING},
{"Fs", "form-string", ARG_STRING},
{"g", "globoff", ARG_BOOL},
@@ -1722,6 +1723,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
case 'b': /* --styled-output */
global->styled_output = toggle;
break;
case 'c': /* --mail-rcpt-ignore-invalid */
config->mail_rcpt_ignore_invalid = toggle;
break;
default: /* --fail (hard on errors) */
config->failonerror = toggle;
}
@@ -1836,6 +1836,10 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->mail_rcpt)
my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);

/* curl 7.70.x */
my_setopt(curl, CURLOPT_MAIL_RCPT_IGNORE_INVALID,
config->mail_rcpt_ignore_invalid ? 1L : 0L);

/* curl 7.20.x */
if(config->ftp_pret)
my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L);

0 comments on commit 74a4bb1

Please sign in to comment.
You can’t perform that action at this time.