mirror of
https://github.com/curl/curl.git
synced 2026-04-15 00:41:41 +03:00
smtp: allow suffix behind a mail address for RFC 3461
Verified in test 3215 Closes #16643
This commit is contained in:
parent
3ccffad28d
commit
450c00f983
6 changed files with 98 additions and 19 deletions
1
.github/scripts/spellcheck.words
vendored
1
.github/scripts/spellcheck.words
vendored
|
|
@ -205,6 +205,7 @@ DoT
|
|||
doxygen
|
||||
drftpd
|
||||
dsa
|
||||
DSN
|
||||
dtrace
|
||||
Dudka
|
||||
Dymond
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ to specify the sender's email address when sending SMTP mail with libcurl.
|
|||
An originator email address should be specified with angled brackets (\<\>)
|
||||
around it, which if not specified are added automatically.
|
||||
|
||||
In order to specify DSN parameters (as per RFC 3461), the address has to be
|
||||
written in angled brackets, followed by the parameters.
|
||||
|
||||
If this parameter is not specified then an empty address is sent to the SMTP
|
||||
server which might cause the email to be rejected.
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ pair of angled brackets (\<\>), however, should you not use an angled bracket
|
|||
as the first character libcurl assumes you provided a single email address and
|
||||
encloses that address within brackets for you.
|
||||
|
||||
In order to specify DSN parameters (as per RFC 3461), the address has to be
|
||||
written in angled brackets, followed by the parameters.
|
||||
|
||||
When performing an address verification (**VRFY** command), each recipient
|
||||
should be specified as the username or username plus domain (as per Section
|
||||
3.5 of RFC 5321).
|
||||
|
|
@ -68,6 +71,7 @@ int main(void)
|
|||
struct curl_slist *list;
|
||||
list = curl_slist_append(NULL, "root@localhost");
|
||||
list = curl_slist_append(list, "person@example.com");
|
||||
list = curl_slist_append(list, "<other@example.com> NOTIFY=SUCCESS");
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "smtp://example.com/");
|
||||
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, list);
|
||||
res = curl_easy_perform(curl);
|
||||
|
|
|
|||
50
lib/smtp.c
50
lib/smtp.c
|
|
@ -169,7 +169,8 @@ static CURLcode smtp_parse_url_path(struct Curl_easy *data,
|
|||
static CURLcode smtp_parse_custom_request(struct Curl_easy *data,
|
||||
struct SMTP *smtp);
|
||||
static CURLcode smtp_parse_address(const char *fqma,
|
||||
char **address, struct hostname *host);
|
||||
char **address, struct hostname *host,
|
||||
const char **suffix);
|
||||
static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech,
|
||||
const struct bufref *initresp);
|
||||
static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech,
|
||||
|
|
@ -620,11 +621,12 @@ static CURLcode smtp_perform_command(struct Curl_easy *data,
|
|||
if((!smtp->custom) || (!smtp->custom[0])) {
|
||||
char *address = NULL;
|
||||
struct hostname host = { NULL, NULL, NULL, NULL };
|
||||
const char *suffix = "";
|
||||
|
||||
/* Parse the mailbox to verify into the local address and hostname
|
||||
parts, converting the hostname to an IDN A-label if necessary */
|
||||
result = smtp_parse_address(smtp->rcpt->data,
|
||||
&address, &host);
|
||||
&address, &host, &suffix);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
|
|
@ -694,11 +696,12 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data,
|
|||
if(data->set.str[STRING_MAIL_FROM]) {
|
||||
char *address = NULL;
|
||||
struct hostname host = { NULL, NULL, NULL, NULL };
|
||||
const char *suffix = "";
|
||||
|
||||
/* Parse the FROM mailbox into the local address and hostname parts,
|
||||
converting the hostname to an IDN A-label if necessary */
|
||||
result = smtp_parse_address(data->set.str[STRING_MAIL_FROM],
|
||||
&address, &host);
|
||||
&address, &host, &suffix);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -709,14 +712,14 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data,
|
|||
(!Curl_is_ASCII_name(host.name)));
|
||||
|
||||
if(host.name) {
|
||||
from = aprintf("<%s@%s>", address, host.name);
|
||||
from = aprintf("<%s@%s>%s", address, host.name, suffix);
|
||||
|
||||
Curl_free_idnconverted_hostname(&host);
|
||||
}
|
||||
else
|
||||
/* An invalid mailbox was provided but we will simply let the server
|
||||
worry about that and reply with a 501 error */
|
||||
from = aprintf("<%s>", address);
|
||||
from = aprintf("<%s>%s", address, suffix);
|
||||
|
||||
free(address);
|
||||
}
|
||||
|
|
@ -734,11 +737,12 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data,
|
|||
if(data->set.str[STRING_MAIL_AUTH][0] != '\0') {
|
||||
char *address = NULL;
|
||||
struct hostname host = { NULL, NULL, NULL, NULL };
|
||||
const char *suffix = "";
|
||||
|
||||
/* Parse the AUTH mailbox into the local address and hostname parts,
|
||||
converting the hostname to an IDN A-label if necessary */
|
||||
result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
|
||||
&address, &host);
|
||||
&address, &host, &suffix);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -750,14 +754,14 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data,
|
|||
utf8 = TRUE;
|
||||
|
||||
if(host.name) {
|
||||
auth = aprintf("<%s@%s>", address, host.name);
|
||||
auth = aprintf("<%s@%s>%s", address, host.name, suffix);
|
||||
|
||||
Curl_free_idnconverted_hostname(&host);
|
||||
}
|
||||
else
|
||||
/* An invalid mailbox was provided but we will simply let the server
|
||||
worry about it */
|
||||
auth = aprintf("<%s>", address);
|
||||
auth = aprintf("<%s>%s", address, suffix);
|
||||
free(address);
|
||||
}
|
||||
else
|
||||
|
|
@ -867,22 +871,24 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data,
|
|||
CURLcode result = CURLE_OK;
|
||||
char *address = NULL;
|
||||
struct hostname host = { NULL, NULL, NULL, NULL };
|
||||
const char *suffix = "";
|
||||
|
||||
/* Parse the recipient mailbox into the local address and hostname parts,
|
||||
converting the hostname to an IDN A-label if necessary */
|
||||
result = smtp_parse_address(smtp->rcpt->data,
|
||||
&address, &host);
|
||||
&address, &host, &suffix);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Send the RCPT TO command */
|
||||
if(host.name)
|
||||
result = Curl_pp_sendf(data, &smtpc->pp, "RCPT TO:<%s@%s>",
|
||||
address, host.name);
|
||||
result = Curl_pp_sendf(data, &smtpc->pp, "RCPT TO:<%s@%s>%s",
|
||||
address, host.name, suffix);
|
||||
else
|
||||
/* An invalid mailbox was provided but we will simply let the server worry
|
||||
about that and reply with a 501 error */
|
||||
result = Curl_pp_sendf(data, &smtpc->pp, "RCPT TO:<%s>", address);
|
||||
result = Curl_pp_sendf(data, &smtpc->pp, "RCPT TO:<%s>%s",
|
||||
address, suffix);
|
||||
|
||||
Curl_free_idnconverted_hostname(&host);
|
||||
free(address);
|
||||
|
|
@ -1868,10 +1874,11 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data,
|
|||
* the address part with the hostname being NULL.
|
||||
*/
|
||||
static CURLcode smtp_parse_address(const char *fqma, char **address,
|
||||
struct hostname *host)
|
||||
struct hostname *host, const char **suffix)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t length;
|
||||
char *addressend;
|
||||
|
||||
/* Duplicate the fully qualified email address so we can manipulate it,
|
||||
ensuring it does not contain the delimiters if specified */
|
||||
|
|
@ -1879,10 +1886,19 @@ static CURLcode smtp_parse_address(const char *fqma, char **address,
|
|||
if(!dup)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
length = strlen(dup);
|
||||
if(length) {
|
||||
if(dup[length - 1] == '>')
|
||||
dup[length - 1] = '\0';
|
||||
if(fqma[0] != '<') {
|
||||
length = strlen(dup);
|
||||
if(length) {
|
||||
if(dup[length - 1] == '>')
|
||||
dup[length - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else {
|
||||
addressend = strrchr(dup, '>');
|
||||
if(addressend) {
|
||||
*addressend = '\0';
|
||||
*suffix = addressend + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the hostname from the address (if we can) */
|
||||
|
|
|
|||
|
|
@ -278,8 +278,7 @@ test3032 test3033 \
|
|||
test3100 test3101 test3102 test3103 test3104 test3105 \
|
||||
\
|
||||
test3200 test3201 test3202 test3203 test3204 test3205 test3207 test3208 \
|
||||
test3209 test3210 test3211 test3212 test3213 test3214 \
|
||||
\
|
||||
test3209 test3210 test3211 test3212 test3213 test3214 test3215 \
|
||||
test4000 test4001
|
||||
|
||||
EXTRA_DIST = $(TESTCASES) DISABLED
|
||||
|
|
|
|||
56
tests/data/test3215
Normal file
56
tests/data/test3215
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
SMTP DSN
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Server-side
|
||||
<reply>
|
||||
# Special Replies, so the server does not have to understand DSN
|
||||
<servercmd>
|
||||
REPLY MAIL 250 Ok
|
||||
REPLY RCPT 250 Ok
|
||||
</servercmd>
|
||||
</reply>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
smtp
|
||||
</server>
|
||||
<name>
|
||||
SMTP DSN
|
||||
</name>
|
||||
<stdin>
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
</stdin>
|
||||
<command>
|
||||
smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt "<recipient@example.com> NOTIFY=SUCCESS,FAILURE" --mail-from "<sender@example.com> RET=HDRS" -T -
|
||||
</command>
|
||||
</client>
|
||||
|
||||
#
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
EHLO %TESTNUMBER
|
||||
MAIL FROM:<sender@example.com> RET=HDRS
|
||||
RCPT TO:<recipient@example.com> NOTIFY=SUCCESS,FAILURE
|
||||
DATA
|
||||
QUIT
|
||||
</protocol>
|
||||
<upload>
|
||||
From: different
|
||||
To: another
|
||||
|
||||
body
|
||||
.
|
||||
</upload>
|
||||
</verify>
|
||||
</testcase>
|
||||
Loading…
Add table
Add a link
Reference in a new issue