11

I am attempting to build a client reporting engine using R/Python, and Sendgrid's Email API. I can send emails, but the last thing that I need to do is attach a client's CSV report.

I have attempted a number of approaches, including base64 encoding the file and writing the string to disk from R to python, but not luck. That said, it seems like I am getting stuck on this error:

TypeError: Object of type 'bytes' is not JSON serializable

My code to get there is:

with open('raw/test-report.csv', 'rb') as fd:
     b64data = base64.b64encode(fd.read())
attachment = Attachment()
attachment.content = b64data
attachment.filename = "your-lead-report.csv"
mail.add_attachment(attachment)

What is confusing is that if I simply replace b64data with the line

attachment.content = 'TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gQ3JhcyBwdW12'

an email is sent with an attachment.

For reference, I have been using:

https://github.com/sendgrid/sendgrid-python

and

kitchen sink tutorial

and haven't had any issues until this final step in my project.

Any help will be greatly appreciated. It's worth noting that my strength is in R, but I usually can hack things together in python with the help of the internets.

0

3 Answers 3

7

You need to convert b64data to a regular string before assigning it to attachment.content. Sendgrid builds a JSON payload which it sends in the requests so it doesn't know how to serialize the value assigned to attachment.content which in this case is a bytestring.

str(b64data,'utf-8')

References:

Sign up to request clarification or add additional context in comments.

1 Comment

That did the trick, thanks! I had played around with variants of this, but nothing in the right sequence. Much appreciated.
5

Here's how to attach an in memory CSV to a sendgrid email:

import base64
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import (
    Mail, Attachment, FileContent, FileName,
    FileType, Disposition)
from io import BytesIO
import pandas as pd

def send_email_with_csv(from_address, to_address, subject, content, dataframe, filename, filetype):
    message = Mail(
        from_email=from_address,
        to_emails=to_address,
        subject=subject,
        html_content=content)
    
    #%% Create buffered csv
    buffer = BytesIO()
    dataframe.to_csv(buffer);
    buffer.seek(0)
    data = buffer.read()
    encoded = base64.b64encode(data).decode()
    
    #%%
    attachment = Attachment()
    attachment.file_content = FileContent(encoded)
    attachment.file_type = FileType(filetype)
    attachment.file_name = FileName(filename)
    attachment.disposition = Disposition('attachment')
    message.attachment = attachment
    try:
        sendgrid_client = SendGridAPIClient('API_KEY')
        response = sendgrid_client.send(message)
        print(response.status_code)
        print(response.body)
        print(response.headers)
    except Exception as e:
        print(e.message)


df = pd.DataFrame(data={'col1': [1, 2], 'col2': [3, 4]})

send_email_with_csv(from_address='[email protected]',
                    to_address='[email protected]',
                    subject='Sending with Twilio SendGrid is Fun',
                    content='<strong>and easy to do anywhere, even with Python</strong>',
                    dataframe=df,
                    filename='spreadsheet.csv',
                    filetype='text/csv')

1 Comment

Useful note to save you time: filetype must be MIME types like here developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/…
0
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import (Mail, Attachment, FileContent, FileName, FileType, Disposition)

def send_email_with_attachment(api_key, sender_email, recipient_email, subject, html_content, attachment_path):
    message = Mail(
        from_email=sender_email,
        to_emails=recipient_email,
        subject=subject,
        html_content=html_content
    )

    with open(attachment_path, 'rb') as attachment_file:
        attachment_data = attachment_file.read()

    encoded_file = os.path.basename(attachment_path)
    attached_file = Attachment(
        FileContent(attachment_data),
        FileName(encoded_file),
        FileType('application/html'),
        Disposition('attachment')
    )

    message.attachment = attached_file

    try:
        sg = SendGridAPIClient(api_key=api_key)
        response = sg.send(message)
        print("Email sent successfully.")
        print(response.status_code)
        print(response.body)
        print(response.headers)
    except Exception as e:
        print("Error sending email.")
        print(str(e))

# Provide your SendGrid API key
api_key = 'YOUR_SENDGRID_API_KEY'

# Provide the sender and recipient email addresses
sender_email = '[email protected]'
recipient_email = '[email protected]'

# Provide the email subject and HTML content
subject = 'Email with HTML attachment'
html_content = '<html><body><h1>Example HTML Email</h1><p>This is an example email with an HTML attachment.</p></body></html>'

# Provide the path to the HTML file you want to attach
attachment_path = 'path/to/attachment.html'

# Send the email
send_email_with_attachment(api_key, sender_email, recipient_email, subject, html_content, attachment_path)

    enter code here

1 Comment

Answer needs supporting information Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.