Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encode CSV file for Sendgrid's Email API

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.

like image 343
Btibert3 Avatar asked Jul 05 '17 18:07

Btibert3


People also ask

How do I send a csv file in SendGrid?

Upload a CSV Use this CSV template to make sure your upload is formatted correctly. Navigate to Marketing > Contacts in the Twilio SendGrid App. Click Add Contacts at the top right corner of the page. Then, select Upload CSV from the menu.

How to Send attachment in mail using SendGrid Node JS?

Attachments can be sent by providing an array of attachments as per the API specification: const sgMail = require('@sendgrid/mail'); sgMail. setApiKey(process. env.


2 Answers

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:

  • https://github.com/sendgrid/sendgrid-python/blob/master/USAGE.md#post-mailsend
like image 140
Oluwafemi Sule Avatar answered Oct 23 '22 13:10

Oluwafemi Sule


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')
like image 3
zelusp Avatar answered Oct 23 '22 13:10

zelusp