Opened 6 months ago

Closed 6 months ago

#36244 closed Bug (invalid)

Email sending with HTML alternative may not generate content

Reported by: WeeDom Owned by:
Component: Core (Mail) Version: 5.1
Severity: Normal Keywords: safestring send_email html_message
Cc: WeeDom Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Trying to render html with some basic inputs from a form. Testing with manage.py test order (order being my app, for the avoidance of doubt)

order_email_to_vendor.html:

<!DOCTYPE html>
<html>
<head>
<title>New Order</title>
</head>
<body>
    <p>Hi, AK,</p>
    <p>An order has been placed by {{ name }}. Details below:</p>
    <ul>
        <li>Name: {{ name }}</li>
        <li>Phone: {{ phone }}</li>
        <li>Email: {{ email }}</li>
        <li>Address: {{ address1 }}</li>
        <li>Comments: {{ comments }}</li>
    </ul>
    <p>Cheers,<br>Your friendly robot helper.</p>
</body>
</html>

my rendering code is this:

context = {
            'name': form.cleaned_data['name'],
            'phone': form.cleaned_data['phone'],
            'email': form.cleaned_data['email'],
            'address1': form.cleaned_data['address1'],
            'comments': form.cleaned_data['comments'],
        }
        # Add this line to inspect the context data
        vendor_email_html = render_to_string('order/order_email_to_vendor.html', context) + " testing by Dom"
        vendor_email_plain = strip_tags(vendor_email_html)

        customer_email_html = render_to_string('order/order_email_to_customer.html', context)
        customer_email_plain = strip_tags(customer_email_html)

        send_mail(
            'New Order',
            vendor_email_plain,
            settings.DEFAULT_FROM_EMAIL,
            [settings.CLIENT_EMAIL],
            fail_silently=False,
            html_message=vendor_email_html,
        )

email sends ok, but with an empty body.

I set a trace in my code. After a LOT of s/n, I came across this. (note - context is generated by manage.py test, not me. And, anyway, context isn't the problem)

> /home/weedom/ak-cakes/venv/lib/python3.12/site-packages/django/template/base.py(1008)render()                                                                                         
-> return SafeString("".join([node.render_annotated(context) for node in self]))                                                                                                        
(Pdb) context                                                                                                                                                                           
[{'True': True, 'False': False, 'None': None}, {'name': 'John Doe', 'phone': '123456789', 'email': 'john@example.com', 'address1': '123 Street', 'comments': 'No nuts, please'}]        
(Pdb) self                                                                                  
[]                                                                                                                                                                                      
(Pdb) SafeString("".join([node.render_annotated(context) for node in self]))                                                                                                            
''   # empty string - template has disappeared.                                                                                       
(Pdb) s                                                                                     
--Return--                                                                                                                                                                              
> /home/weedom/ak-cakes/venv/lib/python3.12/site-packages/django/template/base.py(1008)render()->''                                                                                     
-> return SafeString("".join([node.render_annotated(context) for node in self]))                                                                                                        
(Pdb) s

when it runs the template through SafeString, it returns an empty string. No error/exception.

I've managed to work around this with {% autoescape off %} but that feels *really* icky.

Reporting as a bug because some sort of hint as to what happened would have saved me hours.

Thanks
WeeDom

Change History (1)

comment:1 by Natalia Bidart, 6 months ago

Component: UncategorizedCore (Mail)
Easy pickings: unset
Has patch: unset
Keywords: safestring send_email html_message added; safestring. removed
Resolution: invalid
Status: newclosed
Summary: safestringEmail sending with HTML alternative may not generate content

Hello WeeDom,

With the code that you provided, I created an isolated test case (removing moving pieces), which asserts about the HTML body of the sent email. The test passes and it shows the correct and expected HTML content. The test case:

class OrderTestCase(TestCase):

    def test_ticket_36244(self):
        context = {
            "name": "some name",
            "phone": "some phone",
            "email": "some email",
            "address1": "some address1",
            "comments": "some comments",
        }
        vendor_email_html = (
            render_to_string("order/order_email_to_vendor.html", context)
            + " testing by Dom"
        )
        vendor_email_plain = strip_tags(vendor_email_html)

        mail.send_mail(
            "New Order",
            vendor_email_plain,
            "from@exmaple.com",
            ["client@example.com"],
            fail_silently=False,
            html_message=vendor_email_html,
        )

        self.assertEqual(len(mail.outbox), 1)
        msg = mail.outbox[0]
        expected = """<!DOCTYPE html>
<html>
<head>
<title>New Order</title>
</head>
<body>
    <p>Hi, AK,</p>
    <p>An order has been placed by some name. Details below:</p>
    <ul>
        <li>Name: some name</li>
        <li>Phone: some phone</li>
        <li>Email: some email</li>
        <li>Address: some address1</li>
        <li>Comments: some comments</li>
    </ul>
    <p>Cheers,<br>Your friendly robot helper.</p>
</body>
</html>
 testing by Dom"""
        self.assertEqual(msg.alternatives[0][0], expected)

Because of the above, and lack of reproduction steps, this report seems better suited to be a support request. The best place to get answers to your issue is using any of the user support channels from this link.

Since the goal of this issue tracker is to track issues about Django itself, and your issue seems, at first, to be located in your custom code, I'll be closing this ticket as invalid following the ticket triaging process. If, after debugging, you find out that this is indeed a bug in Django, please re-open with the specific details and please be sure to include a small Django project to reproduce or a failing test case.

I'm also unchecking the "has patch" flag since I can't find a PR for this ticket.

Thank you!

Note: See TracTickets for help on using tickets.
Back to Top