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.
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.
Attachments can be sent by providing an array of attachments as per the API specification: const sgMail = require('@sendgrid/mail'); sgMail. setApiKey(process. env.
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')
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')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With