14

I'm trying to attach a PDF file to my email sent with sendgrid.

Here is my code :

sg = sendgrid.SendGridAPIClient(apikey=os.environ.get('SENDGRID_API_KEY'))

from_email = Email("from@example.com")
subject = "subject"
to_email = Email("to@example.com")
content = Content("text/html", email_body)

pdf = open(pdf_path, "rb").read().encode("base64")
attachment = Attachment()
attachment.set_content(pdf)
attachment.set_type("application/pdf")
attachment.set_filename("test.pdf")
attachment.set_disposition("attachment")
attachment.set_content_id(number)

mail = Mail(from_email, subject, to_email, content)
mail.add_attachment(attachment)

response = sg.client.mail.send.post(request_body=mail.get())

print(response.status_code)
print(response.body)
print(response.headers)

But the Sendgrid Python library is throwing an error HTTP Error 400: Bad Request.

What is wrong with my code ?

John
  • 4,711
  • 9
  • 51
  • 101
  • Could you check if the request is vlid using https://sendgrid.com/docs/Classroom/Send/v3_Mail_Send/sandbox_mode.html – WannaBeCoder Nov 17 '16 at 13:33
  • I think the problem is around the base64 line. If i set the content like here https://github.com/sendgrid/sendgrid-python/blob/ca96c8dcd66224e13b38ab8fd2d2b429dd07dd02/examples/helpers/mail/mail_example.py#L66 it works. But when I'm using my pdf file with base64 encoded I got the error – John Nov 17 '16 at 13:36

5 Answers5

20

I found a solution. I replaced this line :

pdf = open(pdf_path, "rb").read().encode("base64")

By this :

with open(pdf_path, 'rb') as f:
    data = f.read()

encoded = base64.b64encode(data)

Now it works. I can send encoded file in the set_content :

attachment.set_content(encoded)

Note: The answer above works for Sendgrid v2 or lower. For v3 and up use:

encoded = base64.b64encode(data).decode()
iBug
  • 35,554
  • 7
  • 89
  • 134
John
  • 4,711
  • 9
  • 51
  • 101
  • 11
    Just as a side note. You do not need to `f.close()` since the file is closed when exiting the `with` statement. – elgehelge Sep 13 '17 at 15:39
11

This is my solution, Works with Sendgrid V3

    # Where it was uploaded Path.
    file_path = "MY_FILE_PATH"

    with open(file_path, 'rb') as f:
        data = f.read()

    # Encode contents of file as Base 64
    encoded = base64.b64encode(data).decode()

    """Build attachment"""
    attachment = Attachment()
    attachment.content = encoded
    attachment.type = "application/pdf"
    attachment.filename = "my_pdf_attachment.pdf"
    attachment.disposition = "attachment"
    attachment.content_id = "PDF Document file"

    sg = sendgrid.SendGridAPIClient(apikey=settings.SENDGRID_API_KEY)

    from_email = Email("origin@gmail.com")
    to_email = Email('recipient@gmail.com')
    content = Content("text/html", html_content)

    mail = Mail(from_email, 'Attachment mail PDF', to_email, content)
    mail.add_attachment(attachment)

    try:
        response = sg.client.mail.send.post(request_body=mail.get())
    except urllib.HTTPError as e:
        print(e.read())
        exit()
Eddwin Paz
  • 2,842
  • 4
  • 28
  • 48
10

Straight from the Sendgrid docs:

import urllib.request as urllib
import base64
import os
import json
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import (Mail, Attachment, FileContent, FileName, FileType, Disposition, ContentId)

import os
import json
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail

message = Mail(
    from_email='from_email@example.com',
    to_emails='to@example.com',
    subject='Sending with Twilio SendGrid is Fun',
    html_content='<strong>and easy to do anywhere, even with Python</strong>')
file_path = 'example.pdf'
with open(file_path, 'rb') as f:
    data = f.read()
encoded = base64.b64encode(data).decode()
attachment = Attachment()
attachment.file_content = FileContent(encoded)
attachment.file_type = FileType('application/pdf')
attachment.file_name = FileName('test_filename.pdf')
attachment.disposition = Disposition('attachment')
attachment.content_id = ContentId('Example Content ID')
message.attachment = attachment
try:
    sendgrid_client = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
    response = sendgrid_client.send(message)
    print(response.status_code)
    print(response.body)
    print(response.headers)
except Exception as e:
    print(e.message)
shaik moeed
  • 5,300
  • 1
  • 18
  • 54
John R Perry
  • 3,916
  • 2
  • 38
  • 62
1

"How does one attach more than one file to a message?"

Build additional attachments:

file_path = 'test_filename1.pdf'
with open(file_path, 'rb') as f:
    data = f.read()
    f.close()
encoded = base64.b64encode(data).decode()
attachment1 = Attachment()
attachment1.file_content = FileContent(encoded)
attachment1.file_type = FileType('application/pdf')
attachment1.file_name = FileName('test_filename1.pdf')
attachment1.disposition = Disposition('attachment')
attachment1.content_id = ContentId('Example Content ID1')

file_path = 'test_filename2.pdf'
with open(file_path, 'rb') as f:
    data = f.read()
    f.close()
encoded = base64.b64encode(data).decode()
attachment2 = Attachment()
attachment2.file_content = FileContent(encoded)
attachment2.file_type = FileType('application/pdf')
attachment2.file_name = FileName('test_filename2.pdf')
attachment2.disposition = Disposition('attachment')
attachment2.content_id = ContentId('Example Content ID2')

mail.attachment = [attachment1,attachment2]
DaveL17
  • 1,673
  • 7
  • 24
  • 38
amar
  • 11
  • 1
0

The following approach works for me:

    mail = Mail(
        from_email=SendgridEmail(from_email_str),
        to_emails=[To(e) for e in to_emails],
        subject=email_subject,
        html_content=HtmlContent(email_html_content)
    )
    attachment = Attachment(
        file_content=file_content_b64_encoded,
        file_name=filename,
        file_type=file_type,
        disposition='attachment',
        content_id=filename
    )
    mail.add_attachment(attachment)
Evgenii
  • 3,283
  • 3
  • 27
  • 32