]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
smtp: Allow RCPT TO command to fail for some recipients
authorPavel Volgarev <pvolgarev@google.com>
Tue, 14 Jan 2020 22:22:38 +0000 (17:22 -0500)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 21 Jan 2020 09:40:19 +0000 (10:40 +0100)
Introduces CURLOPT_MAIL_RCPT_ALLLOWFAILS.

Verified with the new tests 3002-3007

Closes #4816

22 files changed:
docs/KNOWN_BUGS
docs/cmdline-opts/mail-rcpt-allowfails.d [new file with mode: 0644]
docs/libcurl/curl_easy_setopt.3
docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLLOWFAILS.3 [new file with mode: 0644]
docs/libcurl/opts/Makefile.inc
docs/libcurl/symbols-in-versions
include/curl/curl.h
lib/setopt.c
lib/smtp.c
lib/smtp.h
lib/urldata.h
src/tool_cfgable.h
src/tool_getparam.c
src/tool_help.c
src/tool_operate.c
tests/data/Makefile.inc
tests/data/test3002 [new file with mode: 0644]
tests/data/test3003 [new file with mode: 0644]
tests/data/test3004 [new file with mode: 0644]
tests/data/test3005 [new file with mode: 0644]
tests/data/test3006 [new file with mode: 0644]
tests/data/test3007 [new file with mode: 0644]

index 01c19d4125cb27e15754b3a62bd4ad327bc1021c..ef359467269a7edf167e8b8aff8624f6246eb729 100644 (file)
@@ -35,9 +35,8 @@ problems may have been fixed or changed somewhat since this was written!
  3. Email protocols
  3.1 IMAP SEARCH ALL truncated response
  3.2 No disconnect command
- 3.3 SMTP to multiple recipients
- 3.4 POP3 expects "CRLF.CRLF" eob for some single-line responses
- 3.5 AUTH PLAIN for SMTP is not working on all servers
+ 3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses
+ 3.4 AUTH PLAIN for SMTP is not working on all servers
 
  4. Command line
  4.1 -J and -O with %-encoded file names
@@ -276,21 +275,13 @@ problems may have been fixed or changed somewhat since this was written!
  The disconnect commands (LOGOUT and QUIT) may not be sent by IMAP, POP3 and
  SMTP if a failure occurs during the authentication phase of a connection.
 
-3.3 SMTP to multiple recipients
-
- When sending data to multiple recipients, curl will abort and return failure
- if one of the recipients indicate failure (on the "RCPT TO"
- command). Ordinary mail programs would proceed and still send to the ones
- that can receive data. This is subject for change in the future.
- https://curl.haxx.se/bug/view.cgi?id=1116
-
-3.4 POP3 expects "CRLF.CRLF" eob for some single-line responses
+3.3 POP3 expects "CRLF.CRLF" eob for some single-line responses
 
  You have to tell libcurl not to expect a body, when dealing with one line
  response commands. Please see the POP3 examples and test cases which show
  this for the NOOP and DELE commands. https://curl.haxx.se/bug/?i=740
 
-3.5 AUTH PLAIN for SMTP is not working on all servers
+3.4 AUTH PLAIN for SMTP is not working on all servers
 
  Specifying "--login-options AUTH=PLAIN" on the command line doesn't seem to
  work correctly.
diff --git a/docs/cmdline-opts/mail-rcpt-allowfails.d b/docs/cmdline-opts/mail-rcpt-allowfails.d
new file mode 100644 (file)
index 0000000..b5723df
--- /dev/null
@@ -0,0 +1,15 @@
+Long: mail-rcpt-allowfails
+Help: Allow RCPT TO command to fail for some recipients
+Protocols: SMTP
+Added: 7.69.0
+---
+When sending data to multiple recipients, by default curl will abort SMTP
+conversation if at least one of the recipients causes RCPT TO command to
+return an error.
+
+The default behavior can be changed by passing --mail-rcpt-allowfails
+command-line option which will make curl ignore errors and proceed with the
+remaining valid recipients.
+
+In case when all recipients cause RCPT TO command to fail, curl will abort SMTP
+conversation and return the error received from to the last RCPT TO command.
\ No newline at end of file
index ca558e864a3ff85e873147648aa86f8ee0d3d37c..099ca658c9ad1149775f2fd59ebaeeae3c5b7b86 100644 (file)
@@ -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_ALLLOWFAILS
+Allow RCPT TO command to fail for some recipients. See \fICURLOPT_MAIL_RCPT_ALLLOWFAILS(3)\fP
 .SH TFTP OPTIONS
 .IP CURLOPT_TFTP_BLKSIZE
 TFTP block size. See \fICURLOPT_TFTP_BLKSIZE(3)\fP
diff --git a/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLLOWFAILS.3 b/docs/libcurl/opts/CURLOPT_MAIL_RCPT_ALLLOWFAILS.3
new file mode 100644 (file)
index 0000000..aeff295
--- /dev/null
@@ -0,0 +1,71 @@
+.\" **************************************************************************
+.\" *                                  _   _ ____  _
+.\" *  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_ALLLOWFAILS 3 "16 Jan 2020" "libcurl 7.69.0" "curl_easy_setopt options"
+.SH NAME
+CURLOPT_MAIL_RCPT_ALLLOWFAILS \- allow RCPT TO command to fail for some recipients
+.SH SYNOPSIS
+.nf
+#include <curl/curl.h>
+
+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAIL_RCPT_ALLLOWFAILS,
+                          long allow);
+.SH DESCRIPTION
+If \fIallow\fP is set to 1L, allow RCPT TO command to fail for some recipients.
+
+When sending data to multiple recipients, by default curl will abort SMTP
+conversation if at least one of the recipients causes RCPT TO command to
+return an error.
+
+The default behavior can be changed by setting \fIignore\fP to 1L which will
+make curl ignore errors and proceed with the remaining valid recipients.
+
+In case when all recipients cause RCPT TO command to fail, curl will abort SMTP
+conversation and return the error received from to the last RCPT TO command.
+.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 address */
+  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_ALLLOWFAILS, 1L);
+
+  ret = curl_easy_perform(curl);
+  curl_slist_free_all(list);
+  curl_easy_cleanup(curl);
+}
+.fi
+.SH AVAILABILITY
+Added in 7.69.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), "
index 93c4357d2288af08ec33174e46edfd4aadaa52b1..52bf422f4719ca42cccb4f5170548c63c055d38a 100644 (file)
@@ -188,6 +188,7 @@ man_MANS =                                      \
   CURLOPT_MAIL_AUTH.3                           \
   CURLOPT_MAIL_FROM.3                           \
   CURLOPT_MAIL_RCPT.3                           \
+  CURLOPT_MAIL_RCPT_ALLLOWFAILS.3               \
   CURLOPT_MAXAGE_CONN.3                         \
   CURLOPT_MAXCONNECTS.3                         \
   CURLOPT_MAXFILESIZE.3                         \
index 711d5694b425e073d94a00296b2b610497f44bde..07847f28ba0dce394aef550bcead5f9cccd94544 100644 (file)
@@ -471,6 +471,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_ALLLOWFAILS   7.69.0
 CURLOPT_MAXAGE_CONN             7.65.0
 CURLOPT_MAXCONNECTS             7.7
 CURLOPT_MAXFILESIZE             7.10.8
index 7921acfc5013665c95c8a8423369e5af087094e8..bca7446d2687f52fe5c81a6d2e191577ee7d85ef 100644 (file)
@@ -1937,6 +1937,9 @@ typedef enum {
   /* SASL authorisation identity */
   CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289),
 
+  /* allow RCPT TO command to fail for some recipients */
+  CURLOPT(CURLOPT_MAIL_RCPT_ALLLOWFAILS, CURLOPTTYPE_LONG, 290),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index 5f88ad3afdb600006c4f04c1129e4e9f49f2be60..5a8ccac28f54b67295754eb999ff21a8fa60f51b 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * 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
@@ -2391,6 +2391,10 @@ 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_ALLLOWFAILS:
+    /* allow RCPT TO command to fail for some recipients */
+    data->set.mail_rcpt_allowfails = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    break;
 #endif
 
   case CURLOPT_SASL_AUTHZID:
index 65220b0f683e8673dacbd665154f82cb94c44366..764a1b75ea19b9dbe2fb51f1c7db622938e89c15 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * 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
@@ -915,25 +915,53 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
   CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
   struct SMTP *smtp = data->req.protop;
+  bool is_smtp_err = FALSE;
+  bool is_smtp_blocking_err = FALSE;
 
   (void)instate; /* no use for this yet */
 
-  if(smtpcode/100 != 2) {
-    failf(data, "RCPT failed: %d", smtpcode);
-    result = CURLE_SEND_ERROR;
+  is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE;
+
+  /* If there's multiple RCPT TO to be issued, it's possible to ignore errors
+     and proceed with only the valid addresses. */
+  is_smtp_blocking_err =
+    (is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE;
+
+  if(is_smtp_err) {
+    /* Remembering the last failure which we can report if all "RCPT TO" have
+       failed and we cannot proceed. */
+    smtp->rcpt_last_error = smtpcode;
+
+    if(is_smtp_blocking_err) {
+      failf(data, "RCPT failed: %d", smtpcode);
+      result = CURLE_SEND_ERROR;
+    }
   }
   else {
+    /* Some RCPT TO commands have succeeded. */
+    smtp->rcpt_had_ok = TRUE;
+  }
+
+  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");
+      /* We weren't able to issue a successful RCPT TO command while going
+         over recipients (potentially multiple). Sending back last error. */
+      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 +1315,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;
 
+  /* Track of whether we've successfully sent at least one RCPT TO command */
+  smtp->rcpt_had_ok = FALSE;
+
+  /* Track of the last error we've received by sending RCPT TO command */
+  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;
index 20fc081190ef46d6617a571aae944a8e042161ba..0865d91e7eb0db035aac4e2b111a8657612b08c1 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2009 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2009 - 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
@@ -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 RCPT TO commands (depends on
+                              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 */
index 6aaadca6f5ada57724659aa42bac8837dc7026d6..6882e0a656efc0309c2361dd5a80864436993613 100644 (file)
@@ -1791,6 +1791,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_allowfails); /* allow RCPT TO command to fail for some
+                                recipients */
 };
 
 struct Names {
index 32e811eaa07b88af991053177baf5492896d4994..e093b2c842eded1e263e67702e300d9742a2ac70 100644 (file)
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * 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
@@ -108,6 +108,7 @@ struct OperationConfig {
   char *mail_from;
   struct curl_slist *mail_rcpt;
   char *mail_auth;
+  bool mail_rcpt_allowfails; /* --mail-rcpt-allowfails */
   char *sasl_authzid;       /* Authorisation identity (identity to use) */
   bool sasl_ir;             /* Enable/disable SASL initial response */
   bool proxytunnel;
index 8df6e5e24b65a6ba6b7b4d5efa95b0f449d1697e..b757ac8f04240ac6ead04f2d1506342513aa9d31 100644 (file)
@@ -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-allowfails",     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-allowfails */
+        config->mail_rcpt_allowfails = toggle;
+        break;
       default: /* --fail (hard on errors)  */
         config->failonerror = toggle;
       }
index 8d3f3454766de6a7df48c64f0bb8416f23f8485d..9ee99d174935d8483d5b31516e0743ee9e8d0618 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * 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
@@ -239,6 +239,8 @@ static const struct helptxt helptext[] = {
    "Mail from this address"},
   {"    --mail-rcpt <address>",
    "Mail to this address"},
+  {"    --mail-rcpt-allowfails",
+   "Allow RCPT TO command to fail for some recipients"},
   {"-M, --manual",
    "Display the full manual"},
   {"    --max-filesize <bytes>",
index 2e6563a2008ce166299934244fa2e7ed568d525f..2855f0f8f8ea0e2f6e2c2de64999664291463ae8 100644 (file)
@@ -1835,6 +1835,10 @@ static CURLcode single_transfer(struct GlobalConfig *global,
         if(config->mail_rcpt)
           my_setopt_slist(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
 
+        /* curl 7.69.x */
+        my_setopt(curl, CURLOPT_MAIL_RCPT_ALLLOWFAILS,
+          config->mail_rcpt_allowfails ? 1L : 0L);
+
         /* curl 7.20.x */
         if(config->ftp_pret)
           my_setopt(curl, CURLOPT_FTP_USE_PRET, 1L);
index 51cc920628df7170e5db6d16742429ae110f0782..f72ccbc16dea33e330bc691706820f70d2d8afed 100644 (file)
@@ -208,4 +208,5 @@ test2078 \
 test2080 \
 test2100 \
 \
-test3000 test3001
+test3000 test3001 \
+test3002 test3003 test3004 test3005 test3006 test3007
diff --git a/tests/data/test3002 b/tests/data/test3002
new file mode 100644 (file)
index 0000000..ac68202
--- /dev/null
@@ -0,0 +1,55 @@
+<testcase>
+<info>
+<keywords>
+SMTP
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+smtp
+</server>
+ <name>
+SMTP with multiple and invalid (first) --mail-rcpt and --mail-rcpt-allowfails
+ </name>
+<stdin>
+From: different\r
+To: another\r
+\r
+body\r
+</stdin>
+ <command>
+smtp://%HOSTIP:%SMTPPORT/3002 --mail-rcpt-allowfails --mail-rcpt invalid.one --mail-rcpt recipient.two@example.com --mail-rcpt recipient.three@example.com --mail-rcpt recipient.four@example.com --mail-rcpt recipient.five@example.com --mail-from sender@example.com -T -
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+EHLO 3002\r
+MAIL FROM:<sender@example.com>\r
+RCPT TO:<invalid.one>\r
+RCPT TO:<recipient.two@example.com>\r
+RCPT TO:<recipient.three@example.com>\r
+RCPT TO:<recipient.four@example.com>\r
+RCPT TO:<recipient.five@example.com>\r
+DATA\r
+QUIT\r
+</protocol>
+<upload>
+From: different\r
+To: another\r
+\r
+body\r
+.\r
+</upload>
+</verify>
+</testcase>
diff --git a/tests/data/test3003 b/tests/data/test3003
new file mode 100644 (file)
index 0000000..7515aff
--- /dev/null
@@ -0,0 +1,55 @@
+<testcase>
+<info>
+<keywords>
+SMTP
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+smtp
+</server>
+ <name>
+SMTP with multiple and invalid (last) --mail-rcpt and --mail-rcpt-allowfails
+ </name>
+<stdin>
+From: different\r
+To: another\r
+\r
+body\r
+</stdin>
+ <command>
+smtp://%HOSTIP:%SMTPPORT/3003 --mail-rcpt-allowfails --mail-rcpt recipient.one@example.com --mail-rcpt recipient.two@example.com --mail-rcpt recipient.three@example.com --mail-rcpt recipient.four@example.com --mail-rcpt invalid.five --mail-from sender@example.com -T -
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+EHLO 3003\r
+MAIL FROM:<sender@example.com>\r
+RCPT TO:<recipient.one@example.com>\r
+RCPT TO:<recipient.two@example.com>\r
+RCPT TO:<recipient.three@example.com>\r
+RCPT TO:<recipient.four@example.com>\r
+RCPT TO:<invalid.five>\r
+DATA\r
+QUIT\r
+</protocol>
+<upload>
+From: different\r
+To: another\r
+\r
+body\r
+.\r
+</upload>
+</verify>
+</testcase>
diff --git a/tests/data/test3004 b/tests/data/test3004
new file mode 100644 (file)
index 0000000..e021cde
--- /dev/null
@@ -0,0 +1,55 @@
+<testcase>
+<info>
+<keywords>
+SMTP
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+smtp
+</server>
+ <name>
+SMTP with multiple and invalid (middle) --mail-rcpt and --mail-rcpt-allowfails
+ </name>
+<stdin>
+From: different\r
+To: another\r
+\r
+body\r
+</stdin>
+ <command>
+smtp://%HOSTIP:%SMTPPORT/3004 --mail-rcpt-allowfails --mail-rcpt recipient.one@example.com --mail-rcpt recipient.two@example.com --mail-rcpt invalid.three --mail-rcpt recipient.four@example.com --mail-rcpt recipient.five@example.com --mail-from sender@example.com -T -
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+EHLO 3004\r
+MAIL FROM:<sender@example.com>\r
+RCPT TO:<recipient.one@example.com>\r
+RCPT TO:<recipient.two@example.com>\r
+RCPT TO:<invalid.three>\r
+RCPT TO:<recipient.four@example.com>\r
+RCPT TO:<recipient.five@example.com>\r
+DATA\r
+QUIT\r
+</protocol>
+<upload>
+From: different\r
+To: another\r
+\r
+body\r
+.\r
+</upload>
+</verify>
+</testcase>
diff --git a/tests/data/test3005 b/tests/data/test3005
new file mode 100644 (file)
index 0000000..256555a
--- /dev/null
@@ -0,0 +1,55 @@
+<testcase>
+<info>
+<keywords>
+SMTP
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+smtp
+</server>
+ <name>
+SMTP with multiple and invalid (all but one) --mail-rcpt and --mail-rcpt-allowfails
+ </name>
+<stdin>
+From: different\r
+To: another\r
+\r
+body\r
+</stdin>
+ <command>
+smtp://%HOSTIP:%SMTPPORT/3005 --mail-rcpt-allowfails --mail-rcpt invalid.one --mail-rcpt recipient.two@example.com --mail-rcpt invalid.three --mail-rcpt invalid.four --mail-rcpt invalid.five --mail-from sender@example.com -T -
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+EHLO 3005\r
+MAIL FROM:<sender@example.com>\r
+RCPT TO:<invalid.one>\r
+RCPT TO:<recipient.two@example.com>\r
+RCPT TO:<invalid.three>\r
+RCPT TO:<invalid.four>\r
+RCPT TO:<invalid.five>\r
+DATA\r
+QUIT\r
+</protocol>
+<upload>
+From: different\r
+To: another\r
+\r
+body\r
+.\r
+</upload>
+</verify>
+</testcase>
diff --git a/tests/data/test3006 b/tests/data/test3006
new file mode 100644 (file)
index 0000000..f54d71c
--- /dev/null
@@ -0,0 +1,51 @@
+<testcase>
+<info>
+<keywords>
+SMTP
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+smtp
+</server>
+ <name>
+SMTP with multiple invalid (all) --mail-rcpt and --mail-rcpt-allowfails
+ </name>
+<stdin>
+From: different\r
+To: another\r
+\r
+body\r
+</stdin>
+ <command>
+smtp://%HOSTIP:%SMTPPORT/3006 --mail-rcpt-allowfails --mail-rcpt invalid.one --mail-rcpt invalid.two --mail-rcpt invalid.three --mail-rcpt invalid.four --mail-rcpt invalid.five --mail-from sender@example.com -T -
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+# 55 - CURLE_SEND_ERROR
+<errorcode>
+55
+</errorcode>
+<protocol>
+EHLO 3006\r
+MAIL FROM:<sender@example.com>\r
+RCPT TO:<invalid.one>\r
+RCPT TO:<invalid.two>\r
+RCPT TO:<invalid.three>\r
+RCPT TO:<invalid.four>\r
+RCPT TO:<invalid.five>\r
+QUIT\r
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test3007 b/tests/data/test3007
new file mode 100644 (file)
index 0000000..b0d6902
--- /dev/null
@@ -0,0 +1,47 @@
+<testcase>
+<info>
+<keywords>
+SMTP
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+smtp
+</server>
+ <name>
+SMTP with invalid --mail-rcpt and --mail-rcpt-allowfails
+ </name>
+<stdin>
+From: different\r
+To: another\r
+\r
+body\r
+</stdin>
+ <command>
+smtp://%HOSTIP:%SMTPPORT/3007 --mail-rcpt-allowfails --mail-rcpt invalid.one --mail-from sender@example.com -T -
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+# 55 - CURLE_SEND_ERROR
+<errorcode>
+55
+</errorcode>
+<protocol>
+EHLO 3007\r
+MAIL FROM:<sender@example.com>\r
+RCPT TO:<invalid.one>\r
+QUIT\r
+</protocol>
+</verify>
+</testcase>