使用 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)之间存在差异。这就是导致身份验证失败的原因。