Search code examples
pythongmail-api

Struggling to send email via Gmail API (connection already established)


So I am trying to send an email via the Gmail API. I have all the relevant credentials set up and I know the API connection is working because I am able to send a call to display emails from my inbox (for instance). However, when it comes to sending an email, I keep getting errors.

The code I have is as below:

class GoogleMailClient:
    def __init__(self):
        self.SCOPES = ['https://www.googleapis.com/auth/gmail.modify'] 
        self.creds = self.get_credentials()
        self.service = self.build_gmail_service()

def get_credentials(self):
    creds = None
    if os.path.exists('gmail_token.pickle'):
        with open('gmail_token.pickle', 'rb') as token:
            creds = pickle.load(token)

    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', self.SCOPES)
            creds = flow.run_local_server(port=0)

        with open('gmail_token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    return creds

def build_gmail_service(self):
    return build('gmail', 'v1', credentials=self.creds)

def send_email(self, message_body):
    message = {'raw': message_body}
    self.service.users().messages().send(userId='me', body=message).execute()

def list_messages(self):
    results = self.service.users().messages().list(userId='me').execute()
    messages = results.get('messages', [])
    return messages

def get_message(self, message_id):
    message = self.service.users().messages().get(userId='me', id=message_id).execute()
    return message

def mark_as_read(self, message_id):
    self.service.users().messages().modify(userId='me', id=message_id, body={'removeLabelIds': ['UNREAD']}).execute()

def delete_message(self, message_id):
    self.service.users().messages().delete(userId='me', id=message_id).execute()

gmail_client = GoogleMailClient()

The first code I tried is:

# Compose your email message
subject = "Your Subject Here"
body = "Hey, this is your message body."

# Create the message using the email library
message = email.message.EmailMessage()
message['to'] = "XXX@hotmail.com"
message['subject'] = subject
message.set_content(body)

# Convert the message to a string
message_as_string = message.as_string()

# Encode the message as base64
message_bytes = message_as_string.encode("utf-8")
message_base64 = base64.urlsafe_b64encode(message_bytes).decode("utf-8")

# Create the message in the correct format
message = {'raw': message_base64}

# Send the email
gmail_client.send_email(message)

The error I get is:

HttpError: <HttpError 400 when requesting https://gmail.googleapis.com/gmail/v1/users/me/messages/send?alt=json returned "Invalid value at 'message' (raw), Starting an object on a scalar field". Details: "[{'message': "Invalid value at 'message' (raw), Starting an object on a scalar field", 'reason': 'invalid'}]">

The second code I tried is:

# Assuming you have already initialized the gmail_client and authorized it.

# Compose your email message
subject = "Your Subject Here"
body = "Hey, this is your message body."

# Create the message using the email library
message = email.message.EmailMessage()
message['to'] = "XXX@hotmail.com"
message['subject'] = subject
message.set_content(body)

# Convert the message to a string
message_as_string = message.as_string()

# Encode the message as base64
message_bytes = message_as_string.encode("utf-8")
message_base64 = base64.urlsafe_b64encode(message_bytes).decode("utf-8")

# Create the message in the correct format
message = {'raw': message_base64}

# Send the email using the Gmail API
try:
    gmail_client.users().messages().send_mail(message_body=message).execute()
    print("Email sent successfully!")
except Exception as e:
    print(f"An error occurred: {e}")

The error I get is:

An error occurred: 'GoogleMailClient' object has no attribute 'users'

How can I fix this?


Solution

  • If you want to use the script of The first code I tried is:, how about the following modification?

    From:

    # Create the message in the correct format
    message = {'raw': message_base64}
    
    # Send the email
    gmail_client.send_email(message)
    

    To:

     gmail_client.send_email(message_base64)
    
    • I thought that in your function send_email, the value of message_body has already been put into a value of raw with message = {'raw': message_body}. So, in your script, I thought that message_base64 can be directly used instead of {'raw': message_base64}.

    • When I tested this modification using my account, I confirmed that an email could be sent.

    • About The second code I tried is:, I thought that userId='me' is required to be added like gmail_client.users().messages().send_mail(userId='me', message_body=message).execute().