Encode CSV file for Sendgrid's Email API

Viewed 6731

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.

2 Answers

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='sender@sender.com',
                    to_address='example@recipient.com',
                    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')
Related