Home > Blockchain >  how to send email with attachment through Gmail API
how to send email with attachment through Gmail API

Time:08-09

this may have been asked before but I haven't seen this specific issue, at least not recognizably

I finally figured out how to send an email through the Gmail API, and now need to add attachments, so I edited the code found on Google's API guide basically just adding some arguments and adding in the "message.add_attachment()" part you see below. the issue is that when "message.to_bytes" is called, it starts some infinite loop and I simply cant understand the literature on these two methods. can anyone help me encode this email object so I can send it with the attachments?

my code:

from __future__ import print_function
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import base64
from email.message import EmailMessage
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

SCOPES = ['https://www.googleapis.com/auth/gmail.send']
def send_message(message:str , subject:str, to_email:str, attachments: list=None):
    """Create and send an email message
    Print the returned  message id
    Returns: Message object, including message id    """


    creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    try:
        service = build('gmail', 'v1', credentials=creds)
        message = EmailMessage()

        message.set_content(message)

        # I added this part
        if attachments:
            for attachment in attachments:
                with open(attachment, 'rb') as content_file:
                    content = content_file.read()
                    message.add_attachment(content, maintype='application', subtype= (attachment.split('.')[1]), filename=attachment)

        message['To'] = to_email
        message['From'] = '[email protected]'
        message['Subject'] = subject
        # encoded message
        encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()

        create_message = {
            'raw': message
        }
        # pylint: disable=E1101
        send_message = (service.users().messages().send
                        (userId="me", body=create_message).execute())
        print(F'Message Id: {send_message["id"]}')
    except HttpError as error:
        print(F'An error occurred: {error}')
        send_message = None
    return send_message

the error message

File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\generator.py", line 116, in flatten        
self._write(msg)
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\generator.py", line 181, in _write
self._dispatch(msg)
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\generator.py", line 218, in _dispatch      
meth(msg)
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\generator.py", line 362, in _handle_message    g.flatten(msg.get_payload(0), unixfrom=False, linesep=self._NL)
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\generator.py", line 116, in flatten        
self._write(msg)
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\generator.py", line 181, in _write
self._dispatch(msg)
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\generator.py", line 209, in _dispatch      
main = msg.get_content_maintype()
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\message.py", line 594, in get_content_maintype
ctype = self.get_content_type()
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\message.py", line 578, in get_content_type 
value = self.get('content-type', missing)
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\message.py", line 471, in get
return self.policy.header_fetch_parse(k, v)
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\policy.py", line 159, in header_fetch_parse    if hasattr(value, 'name'):
  File "C:\Users\Cosmo Staff\AppData\Local\Programs\Python\Python310\lib\email\headerregistry.py", line 205, in name      
@property
  File "c:\Users\Cosmo Staff\.vscode\extensions\ms-python.python-2022.12.0\pythonFiles\lib\python\debugpy\_vendored\pydevd\_pydevd_bundle\pydevd_trace_dispatch_regular.py", line 469, in __call__
return None if event == 'call' else NO_FTRACE
RecursionError: maximum recursion depth exceeded in comparison

the full terminal has allot more of that but its allot so I pasted the last few lines

CodePudding user response:

Modification points:

  • In your script, message is used with def send_message(message:str , subject:str, to_email:str, attachments: list=None): and message = EmailMessage(). I think that the reason for your current issue of def send_message(message:str , subject:str, to_email:str, attachments: list=None): is due to this.

  • And also, I think that at create_message = {'raw': message}, an error occurs. Because message is not URL safe base64. I thought that in this case, encoded_message of encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode() should be used here. I thought that this will be your 2nd issue.

When these points are reflected in your script, it becomes as follows.

Modified script:

def send_message(messageBody:str , subject:str, to_email:str, attachments: list=None):
    """Create and send an email message
    Print the returned  message id
    Returns: Message object, including message id    """


    creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    try:
        service = build('gmail', 'v1', credentials=creds)
        message = EmailMessage()

        message.set_content(messageBody)

        # I added this part
        if attachments:
            for attachment in attachments:
                with open(attachment, 'rb') as content_file:
                    content = content_file.read()
                    message.add_attachment(content, maintype='application', subtype= (attachment.split('.')[1]), filename=attachment)

        message['To'] = to_email
        message['From'] = '[email protected]'
        message['Subject'] = subject
        # encoded message
        encoded_message = base64.urlsafe_b64encode(message.as_bytes()).decode()

        create_message = {
            'raw': encoded_message
        }
        # pylint: disable=E1101
        send_message = (service.users().messages().send
                        (userId="me", body=create_message).execute())
        print(F'Message Id: {send_message["id"]}')
    except HttpError as error:
        print(F'An error occurred: {error}')
        send_message = None
    return send_message
  • In this modification, message of def send_message(message:str , subject:str, to_email:str, attachments: list=None): is modified to messageBody. And, create_message = {'raw': message} is modified to create_message = {"raw": encoded_message}.

Note:

  • When I tested the modified script in my environment, I confirmed that the modified script worked. If another error occurs, please show the error message.
  • Related