【问题标题】:gmail python api with python 3 messages().send() gets json serialization error带有python 3 messages().send()的gmail python api获取json序列化错误
【发布时间】:2020-01-23 21:07:36
【问题描述】:

我正在使用 google-api-python-client==1.7.11

我有运行良好的 python 2 代码改编自 https://developers.google.com/gmail/api/v1/reference/users/messages/send

我将我的代码转换为 python 3,并在下面的 urlsafe_b64encode 中看到了一个 TypeError

我的代码:

# standard
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from base64 import urlsafe_b64encode

# pypi
from flask import current_app
from apiclient import errors

def sendmail(subject, fromaddr, toaddr, html, text='', ccaddr=None ):
    '''
    send mail
    :param subject: subject of email
    :param fromaddr: from address to use
    :param toaddr: to address to use, may be list of addresses
    :param html: html to send
    :param text: optional text alternative to send
    '''
    current_app.logger.info('sendmail(): from={}, to={}, cc={}, subject="{}"'.format(fromaddr, toaddr, ccaddr, subject))

    # Create message container - the correct MIME type is multipart/alternative.
    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = fromaddr
    if not isinstance(toaddr, list):
        toaddr = [toaddr]
    msg['To'] = ', '.join(toaddr)
    if ccaddr:
        if not isinstance(ccaddr, list):
            ccaddr = [ccaddr]
        msg['Cc'] = ', '.join(ccaddr)

    # Record the MIME types of both parts - text/plain and text/html.
    # Attach parts into message container.
    # According to RFC 2046, the last part of a multipart message, in this case
    # the HTML message, is best and preferred.
    if text:
        part1 = MIMEText(text, 'plain')
        msg.attach(part1)
    part2 = MIMEText(html, 'html')
    msg.attach(part2)

    # get credentials using the service account file
    gmail = gmail_service_account_login( current_app.config['APP_SERVICE_ACCOUNT_FILE'], 'librarian@steeplechasers.org' )

    try:
        if debug: current_app.logger.debug('sendmail(): msg.as_string()={}'.format(msg.as_string()))
        message = { 'raw' : urlsafe_b64encode(msg.as_string()) }
        sent = gmail.users().messages().send(userId='me', body=message).execute()
        return sent
    except errors.HttpError as error:
        current_app.logger.error('sendmail(): An error occurred: {}'.format(error))
        raise

我修改代码使用as_bytes(),类似于How to solve "a bytes-like object is required, not 'str'" in create_message() function?中提到的

        message = { 'raw' : urlsafe_b64encode(msg.as_bytes()) }

现在我在调用 messages().send() 时看到 json 序列化错误。我看到谷歌 api 表明它在 pypi 上支持 python 3.6。不知道我需要做哪些额外的模组才能让 gmail 界面正常工作。

Traceback (most recent call last):
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\app.py", line 2463, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\app.py", line 2449, in wsgi_app
    response = self.handle_exception(e)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\app.py", line 1866, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\_compat.py", line 39, in reraise
    raise value
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\app.py", line 2446, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\app.py", line 1951, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\app.py", line 1820, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\_compat.py", line 39, in reraise
    raise value
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\views.py", line 89, in view
    return self.dispatch_request(*args, **kwargs)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\flask\views.py", line 163, in dispatch_request
    return meth(*args, **kwargs)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\contracts\views\frontend\eventscalendar.py", line 249, in post
    sendmail( subject, fromlist, tolist, html, ccaddr=cclist )
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\contracts\mailer.py", line 77, in sendmail
    sent = gmail.users().messages().send(userId='me', body=message).execute()
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\googleapiclient\discovery.py", line 789, in method
    actual_path_params, actual_query_params, body_value)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\googleapiclient\model.py", line 158, in request
    body_value = self.serialize(body_value)
  File "C:\Users\lking\Documents\Lou's Software\projects\contracts\contracts\venv\lib\site-packages\googleapiclient\model.py", line 267, in serialize
    return json.dumps(body_value)
  File "C:\Users\lking\AppData\Local\Programs\Python\Python36\lib\json\__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "C:\Users\lking\AppData\Local\Programs\Python\Python36\lib\json\encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\Users\lking\AppData\Local\Programs\Python\Python36\lib\json\encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "C:\Users\lking\AppData\Local\Programs\Python\Python36\lib\json\encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'bytes' is not JSON serializable

【问题讨论】:

    标签: python-3.x google-api


    【解决方案1】:

    是的,我应该在发布问题之前尝试过这个,但希望这会帮助其他正在寻找这个的人。

    基于Convert byte string to base64-encoded string (output not being a byte string),我尝试解码urlsafe_b64encode的字节输出,因此

        message = { 'raw' : urlsafe_b64encode(msg.as_bytes()).decode("utf-8") }
    

    我的最终代码是

    # standard
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    from base64 import urlsafe_b64encode
    
    # pypi
    from flask import current_app
    from apiclient import errors
    
    def sendmail(subject, fromaddr, toaddr, html, text='', ccaddr=None ):
        '''
        send mail
        :param subject: subject of email
        :param fromaddr: from address to use
        :param toaddr: to address to use, may be list of addresses
        :param html: html to send
        :param text: optional text alternative to send
        '''
        current_app.logger.info('sendmail(): from={}, to={}, cc={}, subject="{}"'.format(fromaddr, toaddr, ccaddr, subject))
    
        # Create message container - the correct MIME type is multipart/alternative.
        msg = MIMEMultipart('alternative')
        msg['Subject'] = subject
        msg['From'] = fromaddr
        if not isinstance(toaddr, list):
            toaddr = [toaddr]
        msg['To'] = ', '.join(toaddr)
        if ccaddr:
            if not isinstance(ccaddr, list):
                ccaddr = [ccaddr]
            msg['Cc'] = ', '.join(ccaddr)
    
        # Record the MIME types of both parts - text/plain and text/html.
        # Attach parts into message container.
        # According to RFC 2046, the last part of a multipart message, in this case
        # the HTML message, is best and preferred.
        if text:
            part1 = MIMEText(text, 'plain')
            msg.attach(part1)
        part2 = MIMEText(html, 'html')
        msg.attach(part2)
    
        # get credentials using the service account file
        gmail = gmail_service_account_login( current_app.config['APP_SERVICE_ACCOUNT_FILE'], 'librarian@steeplechasers.org' )
    
        try:
            if debug: current_app.logger.debug('sendmail(): msg.as_string()={}'.format(msg.as_string()))
            message = { 'raw' : urlsafe_b64encode(msg.as_bytes()).decode("utf-8") }
            sent = gmail.users().messages().send(userId='me', body=message).execute()
            return sent
        except errors.HttpError as error:
            current_app.logger.error('sendmail(): An error occurred: {}'.format(error))
            raise
    

    【讨论】:

      猜你喜欢
      • 2016-12-02
      • 2020-04-06
      • 1970-01-01
      • 1970-01-01
      • 2022-01-12
      • 2016-05-09
      • 1970-01-01
      • 2017-06-05
      • 1970-01-01
      相关资源
      最近更新 更多