Gmail python API с python 3 сообщениями (). send () получает json ошибка сериализации - PullRequest
0 голосов
/ 24 января 2020

Я использую google-api- python -client == 1.7.11

У меня был python 2 код, который работал нормально, адаптированный с https://developers.google.com/gmail/api/v1/reference/users/messages/send

Я преобразовал свой код в python 3 и увидел ошибку TypeEr из urlsafe_b64encode ниже

Мой код:

# 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 (), похоже на то, что упомянуто в Как решить, что требуется «похожий на байты объект, а не« str »» в функции create_message ()?

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

Теперь я вижу json ошибка сериализации при вызове messages (). Send (). Я вижу, API Google указывает, что он поддерживает python 3,6 на Pypi. Не уверен, какие дополнительные моды мне нужно сделать, чтобы интерфейс 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

1 Ответ

0 голосов
/ 24 января 2020

Да, я должен был попробовать это до публикации вопроса, но, надеюсь, это поможет кому-то еще, кто ищет это.

На основе Преобразовать строку байтов в строку в кодировке base64 (вывод не будучи строкой байтов) Я попытался расшифровать вывод байтов из 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
...