使用 libcurl 在 smtp 服务器上进行身份验证失败
Authentication on a smtp server fails using libcurl
我尝试使用以下代码发送电子邮件:
#include "optimnet_mail.h"
#include <cstring>
struct upload_status {
int lines_read;
};
static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp){
char *data = static_cast<char*>(userp);
if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
return 0;
}
size_t len = strlen(data);
memcpy(ptr, data, len);
return len;
}
std::string mailText(const std::string destination, const std::string content){
const std::string stringResult =
"To: " + destination +
"\r\nFrom: " + FROM +
"\r\nSubject: Solver has finished\r\n" +
"\r\n" + content + "\r\n";
return stringResult;
}
int sendMail(const std::string destination, const std::string content){
const std::string text = mailText(destination, content);
char *data = new char [text.length()+1];
std::strcpy (data,text.c_str());
CURL *curl;
CURLcode res = CURLE_OK;
struct curl_slist *recipients = NULL;
struct upload_status upload_ctx;
upload_ctx.lines_read = 0;
curl = curl_easy_init();
if(curl) {
/* Set username and password */
curl_easy_setopt(curl, CURLOPT_USERNAME, FROM);
curl_easy_setopt(curl, CURLOPT_PASSWORD, PASS);
//using smtps fails instantly
curl_easy_setopt(curl, CURLOPT_URL, "smtps://" HOST ":" PORT);
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
/* If your server doesn't have a valid certificate, then you can disable
* part of the Transport Layer Security protection by setting the
* CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false).
*/
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
//curl_easy_setopt(curl, CURLOPT_CAINFO, "~/.ssh/known_hosts");
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
// Add two recipients
recipients = curl_slist_append(recipients, destination.c_str());
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
//upload data
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, data);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/* Send the message */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* Free the list of recipients */
curl_slist_free_all(recipients);
/* Always cleanup */
curl_easy_cleanup(curl);
}
delete data;
return (int)res;
}
int main(){
return sendMail(std::string("myemail@mycompany.com"),std::string("Test2"));
}
不幸的是,执行这段代码会得到以下日志:
* Trying 83.166.143.44:465...
* TCP_NODELAY set
* Connected to mail.infomaniak.ch (83.166.143.44) port 465 (#0)
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* Server certificate:
* subject: CN=mail.infomaniak.ch
* start date: Feb 17 22:44:47 2021 GMT
* expire date: May 18 22:44:47 2021 GMT
* subjectAltName: host "mail.infomaniak.ch" matched cert's "mail.infomaniak.ch"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
< 220 mail.infomaniak.com ESMTP ready
> EHLO conway
< 250-mail.infomaniak.com
< 250-PIPELINING
< 250-SIZE
< 250-ETRN
< 250-ENHANCEDSTATUSCODES
< 250-8BITMIME
< 250-DSN
< 250 AUTH PLAIN LOGIN
> AUTH PLAIN
< 334
> Some hash
< 535 5.7.0 Invalid login or password
* Closing connection 0
curl_easy_perform() failed: Login denied
另一方面,当使用这个 curl 命令时:
curl --ssl-reqd --url 'smtps://mail.infomaniak.ch' --user 'user@example.com:password' --mail-from 'user@example.com' --mail-rcpt 'myemail@mycompany.com' --upload-file mail.txt
,邮件确实已发送。
我的代码中是否遗漏了什么?我不明白为什么使用完全相同的登录名和密码会导致身份验证失败。
编辑:感谢 rustyx 和 Sam Varshavchik,我更正了端口问题和内存泄漏问题。
问题是主机(看起来像 <myemail@mycompany.com>
)和用户(看起来像 myemail@mycompany.com
)之间存在差异。这就是导致身份验证失败的原因。
我尝试使用以下代码发送电子邮件:
#include "optimnet_mail.h"
#include <cstring>
struct upload_status {
int lines_read;
};
static size_t payload_source(char *ptr, size_t size, size_t nmemb, void *userp){
char *data = static_cast<char*>(userp);
if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
return 0;
}
size_t len = strlen(data);
memcpy(ptr, data, len);
return len;
}
std::string mailText(const std::string destination, const std::string content){
const std::string stringResult =
"To: " + destination +
"\r\nFrom: " + FROM +
"\r\nSubject: Solver has finished\r\n" +
"\r\n" + content + "\r\n";
return stringResult;
}
int sendMail(const std::string destination, const std::string content){
const std::string text = mailText(destination, content);
char *data = new char [text.length()+1];
std::strcpy (data,text.c_str());
CURL *curl;
CURLcode res = CURLE_OK;
struct curl_slist *recipients = NULL;
struct upload_status upload_ctx;
upload_ctx.lines_read = 0;
curl = curl_easy_init();
if(curl) {
/* Set username and password */
curl_easy_setopt(curl, CURLOPT_USERNAME, FROM);
curl_easy_setopt(curl, CURLOPT_PASSWORD, PASS);
//using smtps fails instantly
curl_easy_setopt(curl, CURLOPT_URL, "smtps://" HOST ":" PORT);
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
/* If your server doesn't have a valid certificate, then you can disable
* part of the Transport Layer Security protection by setting the
* CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false).
*/
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
//curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
//curl_easy_setopt(curl, CURLOPT_CAINFO, "~/.ssh/known_hosts");
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
// Add two recipients
recipients = curl_slist_append(recipients, destination.c_str());
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
//upload data
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, data);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/* Send the message */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* Free the list of recipients */
curl_slist_free_all(recipients);
/* Always cleanup */
curl_easy_cleanup(curl);
}
delete data;
return (int)res;
}
int main(){
return sendMail(std::string("myemail@mycompany.com"),std::string("Test2"));
}
不幸的是,执行这段代码会得到以下日志:
* Trying 83.166.143.44:465...
* TCP_NODELAY set
* Connected to mail.infomaniak.ch (83.166.143.44) port 465 (#0)
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* Server certificate:
* subject: CN=mail.infomaniak.ch
* start date: Feb 17 22:44:47 2021 GMT
* expire date: May 18 22:44:47 2021 GMT
* subjectAltName: host "mail.infomaniak.ch" matched cert's "mail.infomaniak.ch"
* issuer: C=US; O=Let's Encrypt; CN=R3
* SSL certificate verify ok.
< 220 mail.infomaniak.com ESMTP ready
> EHLO conway
< 250-mail.infomaniak.com
< 250-PIPELINING
< 250-SIZE
< 250-ETRN
< 250-ENHANCEDSTATUSCODES
< 250-8BITMIME
< 250-DSN
< 250 AUTH PLAIN LOGIN
> AUTH PLAIN
< 334
> Some hash
< 535 5.7.0 Invalid login or password
* Closing connection 0
curl_easy_perform() failed: Login denied
另一方面,当使用这个 curl 命令时:
curl --ssl-reqd --url 'smtps://mail.infomaniak.ch' --user 'user@example.com:password' --mail-from 'user@example.com' --mail-rcpt 'myemail@mycompany.com' --upload-file mail.txt
,邮件确实已发送。
我的代码中是否遗漏了什么?我不明白为什么使用完全相同的登录名和密码会导致身份验证失败。
编辑:感谢 rustyx 和 Sam Varshavchik,我更正了端口问题和内存泄漏问题。
问题是主机(看起来像 <myemail@mycompany.com>
)和用户(看起来像 myemail@mycompany.com
)之间存在差异。这就是导致身份验证失败的原因。