使用 Gmail 发送大附件时出现错误 10053 API

Error 10053 When Sending Large Attachments using Gmail API

我正在尝试使用 Gmail API 和以下功能发送各种大小的电子邮件。

通常这很完美,但是对于超过 10MB 的附件(这种情况很少见但会发生)我收到 Errno 10053 认为 是因为我在发送时超时包含大附件的消息。

有没有办法通过指定大小或增加超时限制来解决这个问题? Gmail API 文档中提到了大小,但我正在努力了解如何在 Python 中使用或者它是否有帮助。

def CreateMessageWithAttachment(sender, to, cc, subject,
                                message_text, file_dir, filename):
  """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_text: The text of the email message.
    file_dir: The directory containing the file to be attached.
    filename: The name of the file to be attached.

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

  msg = MIMEText(message_text)
  message.attach(msg)

  path = os.path.join(file_dir, filename)
  content_type, encoding = mimetypes.guess_type(path)

  QCoreApplication.processEvents()

  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(path, 'rb')
    msg = MIMEText(fp.read(), _subtype=sub_type)
    fp.close()
  elif main_type == 'image':
    fp = open(path, 'rb')
    msg = MIMEImage(fp.read(), _subtype=sub_type)
    fp.close()
  elif main_type == 'audio':
    fp = open(path, 'rb')
    msg = MIMEAudio(fp.read(), _subtype=sub_type)
    fp.close()
  else:
    fp = open(path, 'rb')
    msg = MIMEBase(main_type, sub_type)
    msg.set_payload(fp.read())
    fp.close()
  QCoreApplication.processEvents()

  msg.add_header('Content-Disposition', 'attachment', filename=filename)
  message.attach(msg)
  return {'raw': base64.urlsafe_b64encode(message.as_string())}



def SendMessage(service, user_id, message, size):
  """Send an email message.

  Args:
    service: Authorized Gmail API service instance.
    user_id: User's email address. The special value "me"
    can be used to indicate the authenticated user.
    message: Message to be sent.

  Returns:
    Sent Message.
  """

  try:
    message = (service.users().messages().send(userId=user_id, body=message)
               .execute())
    QCoreApplication.processEvents()
    return message
  except errors.HttpError, error:
    pass

对于这么大的东西,您需要使用 MEDIA /upload 选项。然后,您可以发送电子邮件至 Gmail 允许的最大数量。有关如何使用 /upload 的文档: https://developers.google.com/gmail/api/v1/reference/users/messages/send

10MB 的限制没有很好的记录。

'g' 是我授权的 api 上下文。 call 方法将在对象上调用 execute。重要的是媒体调用并使用 media_body 和正文参数。这会导致插入带有标签 INBOX 的邮件,并且它至少允许 24MB 的文件。

因为读取超时时间太短,我最终复制了两份:

f fetch 8:9 (flags INTERNALDATE RFC822.SIZE)
* 8 FETCH (RFC822.SIZE 24000720 INTERNALDATE "19-Jul-2007 17:12:26 +0000" FLAGS (\Seen))
* 9 FETCH (RFC822.SIZE 24000720 INTERNALDATE "19-Jul-2007 17:12:26 +0000" FLAGS (\Seen))

示例代码:

import mailbox
import StringIO
import googleapiclient.http

f = 'my-mbox-file.mbox'
params = {}
params[ 'internalDateSource' ] = 'dateHeader'
for m in mailbox.mbox( f, create=False ):
    message_string = m.as_string()
    params[ 'body' ] = { 'labelIds': [ 'INBOX' ] }

    if len(message_string) > 6000000:
        s = StringIO.StringIO()
        s.write( message_string )
        params[ 'media_body' ] = googleapiclient.http.MediaIoBaseUpload(
                            s, mimetype='message/rfc822' )
    else:
        params['body']['raw'] = (
            base64.urlsafe_b64encode( message_string ) )

    g.call( g.auth.users().messages().insert, params )

    try:
        del params[ 'media_body' ]
    except KeyError:
        pass

我成功发送了 insert/send 带有大文件、python 代码的消息。 google api 文档对开发人员不友好,“/upload”问题完全不清楚,也没有很好的记录,这让很多开发人员感到困惑。

最后一行施展魔法:)

def insert_message(service, message):
        try:
                if message['sizeEstimate'] > 6000000:
                        insert_large_message(service, message)
                else:
                        insert_small_message(service, message)
        except:
                print ('Error: ----type: %s, ----value: %s, ----traceback: %s ************' % (sys.exc_info()[0],sys.exc_info()[1],sys.exc_info()[2]))

def insert_small_message(service, message):
        body = {'raw': message['raw'],'labelIds':message['labelIds'],'internalDateSource':'dateHeader'}
        message = service.users().messages().insert(userId='me',body=body).execute()

def insert_large_message(service, message):
        b = io.BytesIO()
        message_bytes = base64.urlsafe_b64decode(str(message['raw']))
        b.write(message_bytes)
        body = {'labelIds':message['labelIds'],'internalDateSource':'dateHeader'}
        media_body = googleapiclient.http.MediaIoBaseUpload(b, mimetype='message/rfc822' )
        print('load big data!')
        message = service.users().messages().insert(userId='me',body=body,media_body=media_body).execute()