C++ libcurl:can';t使用smtp和oauth2通过gmail进行身份验证

C++ libcurl:can';t使用smtp和oauth2通过gmail进行身份验证,c++,smtp,oauth-2.0,gmail,libcurl,C++,Smtp,Oauth 2.0,Gmail,Libcurl,我正在尝试使用libcurl、smtp和oauth2通过gmail发送电子邮件。我已成功获得访问令牌,并已与 https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={access_token} 以确保它实际上是一个有效的访问令牌。然而,每当我尝试验证并发送电子邮件时,它总是抱怨“验证失败:334”。当我用密码行替换oauth2行时,代码工作得非常好 代码如下: static const char *payload_text[]

我正在尝试使用libcurl、smtp和oauth2通过gmail发送电子邮件。我已成功获得访问令牌,并已与

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={access_token}
以确保它实际上是一个有效的访问令牌。然而,每当我尝试验证并发送电子邮件时,它总是抱怨“验证失败:334”。当我用密码行替换oauth2行时,代码工作得非常好

代码如下:

static const char *payload_text[] = {
  "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",
  "To: XXX@gmail.com\r\n",
  "From: XXX@gmail.com\r\n",
  "Subject: SMTP example message\r\n",
  "\r\n", /* empty line to divide headers from body, see RFC5322 */ 
  "The body of the message starts here.\r\n",
  "\r\n",
  "It could be a lot of lines, could be MIME encoded, whatever.\r\n",
  "Check RFC5322.\r\n",
  NULL
};

struct upload_status {
  int lines_read;
};

static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) {
  struct upload_status *upload_ctx = (struct upload_status *)userp;
  const char *data;

  if ((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
    return 0;
  }

  data = payload_text[upload_ctx->lines_read];

  if(data) {
    size_t len = strlen(data);
    memcpy(ptr, data, len);
    upload_ctx->lines_read++;

    return len;
  }

  return 0;
}

void send_email() {
  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) {
    curl_easy_setopt(curl, CURLOPT_USERNAME, "XXX@gmail.com");
    curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, access_token.c_str());
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587/");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "XXX@gmail.com");
    recipients = curl_slist_append(recipients, "XXXX@gmail.com");
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
    curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

    res = curl_easy_perform(curl);

    if (res != CURLE_OK) 
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
          curl_easy_strerror(res));

    curl_slist_free_all(recipients);
    curl_easy_cleanup(curl);
  }
}
static const char*payload_text[]={
“日期:2010年11月29日星期一21:54:29+1100\r\n”,
“至:XXX@gmail.com\r\n“,
“发件人:XXX@gmail.com\r\n“,
“主题:SMTP示例邮件\r\n”,
“\r\n”、/*要将标题与正文分开,请参见RFC5322*/
“邮件正文从这里开始。\r\n”,
“\r\n”,
“可能有很多行,可能是MIME编码的,无论什么。\r\n”,
“检查RFC5322。\r\n”,
无效的
};
结构上载\u状态{
整数行(u read);;
};
静态大小有效负载源(void*ptr、size\t size、size\t nmemb、void*userp){
结构上传状态*上传状态=(结构上传状态*)用户p;
常量字符*数据;
如果((size==0)| |(nmemb==0)| |((size*nmemb)<1)){
返回0;
}
数据=有效载荷\文本[上传\ ctx->行\读取];
如果(数据){
尺寸长度=标准长度(数据);
memcpy(ptr、数据、len);
上传ctx->lines\u read++;
回程透镜;
}
返回0;
}
无效发送电子邮件(){
卷曲*卷曲;
CURLcode res=CURLE_OK;
struct curl_slist*recipients=NULL;
结构上传\状态上传\ ctx;
上传\u ctx.lines\u read=0;
curl=curl_easy_init();
if(curl){
curl\u easy\u setopt(curl,CURLOPT\u用户名,“XXX@gmail.com");
curl_easy_setopt(curl,CURLOPT_XOAUTH2_承载,访问令牌.c_str());
curl\u easy\u setopt(curl,CURLOPT\u URL,“smtp://smtp.gmail.com:587/");
curl_easy_setopt(curl,CURLOPT_USE_SSL,(long)CURLUSESSL_ALL);
curl_easy_setopt(curl,CURLOPT_MAIL_FROM,“XXX@gmail.com");
recipients=curl\u slist\u append(收件人)XXXX@gmail.com");
curl\u easy\u setopt(curl、CURLOPT\u MAIL\u RCPT、收件人);
curl\u easy\u setopt(curl,CURLOPT\u READFUNCTION,payload\u source);
curl\u easy\u setopt(curl、CURLOPT\u READDATA和upload\u ctx);
卷曲度(卷曲度,卷曲度(1L));
卷曲轻松设置(卷曲,卷曲上传,1L);
res=旋度(curl)\u容易执行(curl);
如果(res!=卷曲(OK)
fprintf(stderr,“curl\u easy\u perform()失败:%s\n”,
卷曲(容易的);
所有(收件人)免费提交;
旋度\轻松\清洁(旋度);
}
}
下面是错误消息的后半部分(不同之处并显示故障):

<250-mx.google.com为您服务,[108.200.141.166]
<250-尺寸35882577
<250-8bit
<250-AUTH登录普通xauth xauth2普通CLIENTTOKEN
<250-增强状态码
<250分块
>AUTH XOAUTH2
< 334 
>DXNLCJ1YY3DTY3NJCM9VZ2VAZ21HAWUY29TAWF1DGG9QMVHCMVYILHMJKUS2DCUVHCU1ZZSVPCQ1I4QUFBQZVUCMDes2G3TZBQZ01JU25ZRGGSJC0C1M2N0Z5CUQYCUKGZDFRv3CBAQ==
<334 EYJZDGF0DXMIOII0MdailcJZY2HLBWVZIJOIQMVHCMVYIWIC2 VcGuijodhrwczovl21Hawwuz29VZ2XLMNVBS8IFQ==
*身份验证失败:334
*正在关闭连接0
curl\u easy\u perform()失败:登录被拒绝
有人能解释一下这里出了什么问题吗?更糟糕的是,我将使用用户名/密码组合登录,但我更想弄清楚这里出了什么问题(我当时的印象是oauth2方式是首选方式)


提前感谢您的帮助。

我也有同样的问题;你解决过这个问题吗?已经有一段时间了,但我认为问题在于访问令牌被切碎(出于某种原因)。我想不出一个非常干净的方法,但基本上我抓住了返回字符串的两个部分,并将第二部分追加到第一部分。然后它成功了。差不多吧。很抱歉说得含糊不清。
< 250-mx.google.com at your service, [108.200.141.166]
< 250-SIZE 35882577
< 250-8BITMIME
< 250-AUTH LOGIN PLAIN XOAUTH XOAUTH2 PLAIN-CLIENTTOKEN
< 250-ENHANCEDSTATUSCODES
< 250 CHUNKING
> AUTH XOAUTH2
< 334 
> dXNlcj1yY3dtY3Njcm9vZ2VAZ21haWwuY29tAWF1dGg9QmVhcmVyIHlhMjkuS2dCUVhCU1ZzSVpCQ1I4QUFBQzVucmdES2g3TzBQZ01JU25zRGlGSjc0c1M2N0Z5cUQycUJrVkgzdHFrV3cBAQ==
< 334 eyJzdGF0dXMiOiI0MDAiLCJzY2hlbWVzIjoiQmVhcmVyIiwic2NvcGUiOiJodHRwczovL21haWwuZ29vZ2xlLmNvbS8ifQ==
* Authentication failed: 334
* Closing connection 0
curl_easy_perform() failed: Login denied