Sendgrid-python: Raises 400 when adding an attachment

Created on 9 Aug 2016  路  5Comments  路  Source: sendgrid/sendgrid-python

Issue Summary

I'm using this library with my Django(1.9.3) app. It works in all cases except the one with attachments where is raises 400 bad request.

Here's my code which creates the attachment:

import csv
from io import StringIO

import sendgrid
from sendgrid.helpers.mail import *

from django.conf import settings


def _send_email(to, subject, body_html, from_email, body_text='', cc=[], bcc=[], **kwargs):
    sg = sendgrid.SendGridAPIClient(apikey=settings.SENDGRID_API_KEY)
    from_email = Email(from_email)
    personalization = Personalization()

    # Add recepients
    if isinstance(to, (list, tuple)):
        for i in to:
            personalization.add_to(Email(i))
        message = Mail(from_email, subject, Email(to[0]), Content('text/html', body_html))
    else:
        personalization.add_to(Email(to))
        message = Mail(from_email, subject, Email(to), Content('text/html', body_html))

    # Add CCs if available
    if cc:
        if isinstance(cc, (list, tuple)):
            for i in cc:
                personalization.add_cc(Email(i))
        else:
            personalization.add_cc(Email(cc))

    # Add BCCs if available
    if bcc:
        if isinstance(bcc, (list, tuple)):
            for i in bcc:
                personalization.add_bcc(Email(i))
        else:
            personalization.add_bcc(Email(bcc))

    message.add_personalization(personalization)

    # Add attachments
    if kwargs.get('attachments'):
        if isinstance(kwargs['attachments'], (list, tuple)):
            for attachment in kwargs['attachments']:
                message.add_attachment(attachment)
        else:
            message.add_attachment(kwargs['attachments'])
    message.set_reply_to(from_email)
    print(message.get())
    sg.client.mail.send.post(request_body=message.get())


csvfile = StringIO()
csvwriter = csv.writer(csvfile)
csvwriter.writerow(['hello', 'world'])
attachment = Attachment()
attachment.set_content(csvfile.getvalue())
attachment.set_type('text/csv')
attachment.set_filename('request.csv')
attachment.set_disposition('attachment')
attachment.set_content_id('request')
_send_email(
    'some_address@some_host.com',
    'New Request',
    'foo bar',
    'another_address@another_host.com',
    attachments=attachment
)

Technical details:

  • sendgrid-python Version: 3.1.9
  • Python Version: 3.5

This is probably not a bug in the library but I'm doing something wrong here. Please help me with this.

help wanted question

Most helpful comment

base64.b64encode(csvfile.getvalue().encode()).decode() works great. Thanks!

All 5 comments

Hello @debugger22,

attachment.set_content() expects a base64 value.

Please see: https://docs.python.org/3/library/base64.html#base64.b64encode

Thanks!

Thanks for the reply @thinkingserious!

In [9]: csvfile.getvalue()
Out[9]: 'hello,world\r\n'

In [10]: bytearray(csvfile.getvalue(), 'utf-8')
Out[10]: bytearray(b'hello,world\r\n')

In [11]: base64.b64encode(bytearray(csvfile.getvalue(), 'utf-8'))
Out[11]: b'aGVsbG8sd29ybGQNCg=='

After doing this, I am getting

TypeError: b'aGVsbG8sd29ybGQNCg==' is not JSON serializable

base64.b64encode(csvfile.getvalue().encode()).decode() works great. Thanks!

Thanks for sharing the solution @debugger22!

@debugger22,

I just noticed another issue in the code. It looks like you are adding a new personalization object when you add a cc or bcc.

The Mail constructor creates a personalization object for you. Here is an example of how to add to it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bishnusyangja picture bishnusyangja  路  4Comments

hugomallinson picture hugomallinson  路  3Comments

andriisoldatenko picture andriisoldatenko  路  4Comments

cl1ent picture cl1ent  路  5Comments

thinkingserious picture thinkingserious  路  3Comments