Skip to content

Commit a1380b8

Browse files
committed
SendGrid: force empty text and html to " " with template_id
Work around an unexpected limitation in SendGrid template rendering, where template text or html bodies are omitted if the supplied message text or html is "". Changing empty string to " " works around the issue. https://sendgrid.com/docs/API_Reference/Web_API_v3/Transactional_Templates/smtpapi.html#-Text-or-HTML-Templates Closes #32
1 parent 771ed51 commit a1380b8

File tree

3 files changed

+27
-0
lines changed

3 files changed

+27
-0
lines changed

anymail/backends/sendgrid.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,12 @@ def set_track_opens(self, track_opens):
290290
def set_template_id(self, template_id):
291291
self.add_filter('templates', 'enable', 1)
292292
self.add_filter('templates', 'template_id', template_id)
293+
# Must ensure text and html are non-empty, or template parts won't render.
294+
# https://sendgrid.com/docs/API_Reference/Web_API_v3/Transactional_Templates/smtpapi.html#-Text-or-HTML-Templates
295+
if not self.data.get("text", ""):
296+
self.data["text"] = " "
297+
if not self.data.get("html", ""):
298+
self.data["html"] = " "
293299

294300
def set_merge_data(self, merge_data):
295301
# Becomes smtpapi['sub'] in build_merge_data, after we know recipients and merge_field_format.

docs/esps/sendgrid.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,20 @@ your SendGrid template definition where you want the message-specific versions
282282
to appear). If you don't want to supply any additional subject or body content
283283
from your Django app, set those EmailMessage attributes to empty strings.
284284

285+
(Anymail will convert empty text and HTML bodies to single spaces whenever
286+
:attr:`~anymail.message.AnymailMessage.template_id` is set, to ensure the
287+
plaintext and HTML from your template are present in your outgoing email.
288+
This works around a `limitation in SendGrid's template rendering`_.)
289+
285290
See the `SendGrid's template overview`_ and `transactional template docs`_
286291
for more information.
287292

288293
.. _SendGrid's template overview:
289294
https://sendgrid.com/docs/User_Guide/Transactional_Templates/index.html
290295
.. _transactional template docs:
291296
https://sendgrid.com/docs/API_Reference/Web_API_v3/Transactional_Templates/smtpapi.html
297+
.. _limitation in SendGrid's template rendering:
298+
https://sendgrid.com/docs/API_Reference/Web_API_v3/Transactional_Templates/smtpapi.html#-Text-or-HTML-Templates
292299

293300

294301
.. _sendgrid-webhooks:

tests/test_sendgrid_backend.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,13 +400,27 @@ def test_tracking(self):
400400
self.assertEqual(smtpapi['filters']['opentrack'], {'settings': {'enable': 0}})
401401

402402
def test_template_id(self):
403+
self.message.attach_alternative("HTML Body", "text/html")
403404
self.message.template_id = "5997fcf6-2b9f-484d-acd5-7e9a99f0dc1f"
404405
self.message.send()
405406
smtpapi = self.get_smtpapi()
406407
self.assertEqual(smtpapi['filters']['templates'], {
407408
'settings': {'enable': 1,
408409
'template_id': "5997fcf6-2b9f-484d-acd5-7e9a99f0dc1f"}
409410
})
411+
data = self.get_api_call_data()
412+
self.assertEqual(data['text'], "Text Body")
413+
self.assertEqual(data['html'], "HTML Body")
414+
415+
def test_template_id_with_empty_body(self):
416+
# Text and html must be present (and non-empty-string), or the corresponding
417+
# part will not render from the template. Make sure we fill in strings:
418+
message = mail.EmailMessage(from_email='[email protected]', to=['[email protected]'])
419+
message.template_id = "5997fcf6-2b9f-484d-acd5-7e9a99f0dc1f"
420+
message.send()
421+
data = self.get_api_call_data()
422+
self.assertEqual(data['text'], " ") # single space is sufficient
423+
self.assertEqual(data['html'], " ")
410424

411425
def test_merge_data(self):
412426
self.message.from_email = '[email protected]'

0 commit comments

Comments
 (0)