sendgrid-python icon indicating copy to clipboard operation
sendgrid-python copied to clipboard

sendgrid.helpers.mail.mail.Mail.from_EmailMessage raises an error from within the sendgrid library

Open kaya-zekioglu opened this issue 4 years ago • 3 comments

Issue Summary

sendgrid.helpers.mail.mail.Mail.from_EmailMessage raises an error from within the sendgrid library.

For some context:

  • I have code which sends composes and sends emails using python's email package.
  • I wish to use sendgrid to handle sending the emails as my SMTP proxy service in lieu of AWS SES or some other similar service.
  • AWS SES offers a send_raw_email method which accepts the result of invoking email.message.EmailMessage.as_bytes() and as such is compatible with my existing code which composes these emails.
  • I looked at the sendgrid library and this from_EmailMessage classmethod appears to provide a similar bridge from python's native email to provider specific API parameter.
  • However as documented in this issue it appears that this classmethod is not functional in the latest version of your library.
    • As a side note: now that this error lead me to look at the implementation of this classmethod it does appear to be too simplistic to account for the complexity of a generic email object. In particular this line would likely raise error if the content were not representable as a string (i.e. the Multipart Content-Type.)

Steps to Reproduce

  1. Create an instance of a very simple python email.message.EmailMessage (https://docs.python.org/3/library/email.examples.html)
  2. Try to convert it to sendgrid.helpers.mail.mail.Mail using the from_EmailMessage classmethod

Code Snippet

from email.message import EmailMessage
msg = EmailMessage()
msg.set_content('CONTENT')
msg['Subject'] = 'SUBJECT'
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'

from sendgrid import Mail
Mail.from_EmailMessage(msg)

Exception/Log

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/conda/lib/python3.7/site-packages/sendgrid/helpers/mail/mail.py", line 1000, in from_EmailMessage
    to_emails=Email(message.get('To')),
  File "/opt/conda/lib/python3.7/site-packages/sendgrid/helpers/mail/mail.py", line 72, in __init__
    self.add_to(to_emails, global_substitutions, is_multiple)
  File "/opt/conda/lib/python3.7/site-packages/sendgrid/helpers/mail/mail.py", line 276, in add_to
    self._set_emails(to_email, global_substitutions, is_multiple, p)
  File "/opt/conda/lib/python3.7/site-packages/sendgrid/helpers/mail/mail.py", line 180, in _set_emails
    personalization.add_email(emails)
  File "/opt/conda/lib/python3.7/site-packages/sendgrid/helpers/mail/personalization.py", line 29, in add_email
    raise ValueError('Please use a To, Cc or Bcc object.')
ValueError: Please use a To, Cc or Bcc object.

Technical details:

  • sendgrid-python version: 6.6.0
  • python version: 3.7.7

kaya-zekioglu avatar Mar 17 '21 17:03 kaya-zekioglu

@kaya-zekioglu This issue has been added to our internal backlog to be prioritized. Pull requests and +1s on the issue summary will help it move up the backlog.

shwetha-manvinkurke avatar Mar 18 '21 21:03 shwetha-manvinkurke

same error. this method is totally broken

micahjsmith avatar Jun 12 '24 18:06 micahjsmith

here is an implementation that does work for simple cases (untested for complex cases)

import email.message
from sendgrid.helpers.mail import Content, From, Header, HtmlContent, Mail, To

# See https://www.twilio.com/docs/sendgrid/api-reference/mail-send/errors#headers-errors
SENDGRID_HEADER_RESERVED_KEYS = (
    "x-sg-id",
    "x-sg-eid",
    "received",
    "dkim-signature",
    "Content-Type",
    "Content-Transfer-Encoding",
    "To",
    "From",
    "Subject",
    "Reply-To",
    "CC",
    "BCC",
)


def email_message_to_sendgrid_mail(message: email.message.EmailMessage) -> Mail:
    mail = Mail(
        from_email=From(message.get("From")),
        to_emails=To(message.get("To")),
        subject=message.get("Subject"),
    )
    mail.add_content(Content(message.get_content_type(), message.get_content().strip()))
    for k, v in message.items():
        if all(k.lower() != rk.lower() for rk in SENDGRID_HEADER_RESERVED_KEYS):
            logger.debug(f"Adding header {k}: {v}")
            mail.add_header(Header(k, v))
    return mail

python 3.11 sendgrid 6.11

micahjsmith avatar Jun 12 '24 20:06 micahjsmith