400错误,需要收件人地址,curl

fcg9iug3  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(162)

我使用了带有curl的Gmail API。(Users.messages: send
但我收到错误400需要收件人地址。

命令

curl -X POST -H "Authorization: Bearer *****" -H "Content-Type:message/rfc822" -d "{'raw':'Encoded Value'}" "https://www.googleapis.com/upload/gmail/v1/users/me/messages/send"

回应

{
   "error": {
     "errors": [
        {
         "domain": "global",
         "reason": "invalidArgument",
         "message": "Recipient address required"
       }
     ],
     "code": 400,
     "message": "Recipient address required"
   }
 }

编码值是由以下python脚本创建的。

import base64
from email.mime.text import MIMEText
from email.utils import formatdate

MAIL_FROM = "example@gmail.com"
MAIL_TO = "example@gmail.com"

def create_message():
    message = MIMEText("Gmail body: Hello world!")
    message["from"] = MAIL_FROM
    message["to"] = MAIL_TO
    message["subject"] = "gmail api test"
    message["Date"] = formatdate(localtime=True)

    byte_msg = message.as_string().encode(encoding="UTF-8")
    byte_msg_b64encoded = base64.urlsafe_b64encode(byte_msg)
    str_msg_b64encoded = byte_msg_b64encoded.decode(encoding="UTF-8")

    return {"raw": str_msg_b64encoded}

print(create_message())
n6lpvg4x

n6lpvg4x1#

当使用https://www.googleapis.com/upload/gmail/v1/users/me/messages/send通过媒体上传请求发送消息时,需要创建请求正文,如下所示。我修改了您的python脚本来创建请求正文。请确认。

修改的python脚本:

import base64
from email.mime.text import MIMEText
from email.utils import formatdate

MAIL_FROM = "example@gmail.com"
MAIL_TO = "example@gmail.com"

def encode(v):
    byte_msg = v.encode(encoding="UTF-8")
    byte_msg_b64encoded = base64.b64encode(byte_msg)
    return byte_msg_b64encoded.decode(encoding="UTF-8")

def create_message():
    message = "To: " + MAIL_TO + "\n"
    message += "From: " + MAIL_FROM + "\n"
    message += "Subject: =?utf-8?B?" + encode("gmail api test") + "?=\n"
    message += "Date: " + formatdate(localtime=True) + "\n"
    message += "Content-Type: multipart/alternative; boundary=boundaryboundary\n\n"
    message += "--boundaryboundary\n"
    message += "Content-Type: text/plain; charset=UTF-8\n"
    message += "Content-Transfer-Encoding: base64\n\n"
    message += encode("Hello world!") + "\n\n"
    message += "--boundaryboundary"
    return message

print(create_message())

结果:

To: example@gmail.com
From: example@gmail.com
Subject: =?utf-8?B?Z21haWwgYXBpIHRlc3Q=?=
Date: Thu, 15 Mar 2018 01:23:45 +0100
Content-Type: multipart/alternative; boundary=boundaryboundary

--boundaryboundary
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64

SGVsbG8gd29ybGQh

--boundaryboundary

请将以上请求正文另存为文本文件。作为示例,文件名为sample.txt

要点:

这里,请注意文件的“EOF”位置。请不要在最后一个--boundaryboundary之后中断。如果在最后一个--boundaryboundary之后中断,则无法接收正文。图像如下。

curl 命令:

curl -s -X POST \
  -H "Authorization: Bearer *****" \
  -H "Content-Type: message/rfc822" \
  --data-binary "@sample.txt" \
  "https://www.googleapis.com/upload/gmail/v1/users/me/messages/send"

它将sample.txt作为二进制数据发布。

结果:

{
 "id": "#####",
 "threadId": "#####",
 "labelIds": [
  "UNREAD",
  "SENT",
  "INBOX"
 ]
}

备注:

  • 这是一个非常简单的示例,因此请根据您的环境对其进行修改。
  • 此答案假设您的访问令牌可用于此情况。如果发生与访问令牌相关的错误,请检查作用域。

如果我误解了你的问题,对不起。

olmpazwi

olmpazwi2#

我想感谢其他有帮助的回答。我的用例要求我使用从Gmail获得的用户访问令牌,并回复给定的邮件线程。
在此,我不得不将Tanaike给出的上述答案修改为以下内容。

import base64
import mimetypes
import os
import traceback
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

import httplib2
from apiclient import discovery
from oauth2client.client import AccessTokenCredentials

def send_message(access_token: str, sender: str, to: str, subject: str, html_message: str, thread_id: str,
                 user_id: str = 'me', attachment_file=None):
    try:
        # Referenced from: https://oauth2client.readthedocs.io/en/latest/source/oauth2client.client.html
        credentials = AccessTokenCredentials(access_token, 'PostmanRuntime/7.29.2')
        http = credentials.authorize(httplib2.Http())
        service = discovery.build('gmail', 'v1', http=http)
        if attachment_file:
            message_body = __create_message_with_attachment__(sender, to, subject, html_message, thread_id, attachment_file)
        else:
            message_body = __create_message_body__(sender, to, subject, html_message, thread_id)
        response = (service.users().messages().send(userId=user_id, body=message_body).execute())
        print(response)
        return response['id']
    except Exception as e:
        traceback.print_exc()

def __create_message_body__(from_email: str, to_email: str, subject: str, message_body: str, thread_id: str):
    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = from_email
    msg['To'] = to_email
    msg.attach(MIMEText(message_body, 'plain'))
    msg.attach(MIMEText(message_body, 'html'))
    return {
        'raw': base64.urlsafe_b64encode(msg.as_string().encode()).decode(),
        'threadId': thread_id
    }

def __create_message_with_attachment__(sender: str, to: str, subject: str, message_body, thread_id: str,
                                   attachment_file: str):
    """Create a message for an email.

    Args:
      sender: Email address of the sender.
      to: Email address of the receiver.
      subject: The subject of the email message.
      message_body: Html message to be sent
      thread_id: thread id to respond to
      attachment_file: The path to the file to be attached.

    Returns:
      An object containing a base64url encoded email object.
    """
    message = MIMEMultipart('mixed')
    message['to'] = to
    message['from'] = sender
    message['subject'] = subject

    message_alternative = MIMEMultipart('alternative')
    message_related = MIMEMultipart('related')

    message_related.attach(MIMEText(message_body, 'html'))
    message_alternative.attach(MIMEText(message_body, 'plain'))
    message_alternative.attach(message_related)

    message.attach(message_alternative)

    print("create_message_with_attachment: file: %s" % attachment_file)
    content_type, encoding = mimetypes.guess_type(attachment_file)

    if content_type is None or encoding is not None:
        content_type = 'application/octet-stream'
    main_type, sub_type = content_type.split('/', 1)
    if main_type == 'text':
        fp = open(attachment_file, 'rb')
        msg = MIMEText(fp.read(), _subtype=sub_type)
        fp.close()
    elif main_type == 'image':
        fp = open(attachment_file, 'rb')
        msg = MIMEImage(fp.read(), _subtype=sub_type)
        fp.close()
    elif main_type == 'audio':
        fp = open(attachment_file, 'rb')
        msg = MIMEAudio(fp.read(), _subtype=sub_type)
        fp.close()
    else:
        fp = open(attachment_file, 'rb')
        msg = MIMEBase(main_type, sub_type)
        msg.set_payload(fp.read())
        fp.close()
    filename = os.path.basename(attachment_file)
    msg.add_header('Content-Disposition', 'attachment', filename=filename)
    message.attach(msg)
    return {
        'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode(),
        'threadId': thread_id
    }

def main():
    to = "example@gmail.com"
    sender = "example@gmail.com"
    subject = "subject"
    message = "Hi<br/>same message here"
    access_token = "ya29.a0AVA9y1uc1Ec-................"
    thread_id = '181b9292e6a.....'

    send_message(access_token=access_token,
                 sender=sender,
                 to=to,
                 subject=subject,
                 html_message=message,
                 thread_id=thread_id)

if __name__ == '__main__':
    main()

请注意我是如何使用用户的访问令牌构造所需凭据的;

credentials = AccessTokenCredentials(access_token, 'user agent here')

这是从https://oauth2client.readthedocs.io/en/latest/source/oauth2client.client.html获取的

相关问题