Selaa lähdekoodia

add: use_jinja to disable Jinja

Mikael Koli 3 vuotta sitten
vanhempi
sitoutus
7e0cbd78ec

+ 27 - 1
docs/tutorials/jinja_support.rst

@@ -113,4 +113,30 @@ as if statements, for loops, macros etc. Here is a quick illustration:
     )
     )
 
 
 Please see `Jinja documentation <https://jinja.palletsprojects.com/>`_ 
 Please see `Jinja documentation <https://jinja.palletsprojects.com/>`_ 
-for more.
+for more.
+
+
+Disabling Jinja
+---------------
+
+In case you wish to pass raw text/HTML and don't want to use Jinja
+to render the bodies, you may also disable it:
+
+.. code-block:: python
+
+    email.send(
+        subject='email subject',
+        receivers=['first.last@example.com'],
+        text="""
+        Hi,
+        {{ these brackets are not processed }}
+        """,
+        html="""
+        <h1>Hi!</h1>
+        <p>
+            {{ these brackets are not processed }}
+        </p>
+        """,
+        use_jinja=False
+    )
+

+ 13 - 10
redmail/email/body.py

@@ -39,9 +39,10 @@ class BodyImage:
 
 
 class Body:
 class Body:
 
 
-    def __init__(self, template:Template=None, table_template:Template=None):
+    def __init__(self, template:Template=None, table_template:Template=None, use_jinja=True):
         self.template = template
         self.template = template
         self.table_template = table_template
         self.table_template = table_template
+        self.use_jinja = use_jinja
 
 
     def render_body(self, body:str, jinja_params:dict):
     def render_body(self, body:str, jinja_params:dict):
         if body is not None and self.template is not None:
         if body is not None and self.template is not None:
@@ -79,7 +80,8 @@ class Body:
 class TextBody(Body):
 class TextBody(Body):
 
 
     def attach(self, msg:EmailMessage, text:str, **kwargs):
     def attach(self, msg:EmailMessage, text:str, **kwargs):
-        text = self.render(text, **kwargs)
+        if self.use_jinja:
+            text = self.render(text, **kwargs)
         msg.set_content(text)
         msg.set_content(text)
 
 
 
 
@@ -109,16 +111,17 @@ class HTMLBody(Body):
             jinja_params : dict
             jinja_params : dict
                 Extra Jinja parameters for the HTML.
                 Extra Jinja parameters for the HTML.
         """
         """
-        domain = parseaddr(msg["from"])[1].split("@")[-1] if self.domain is None else self.domain
-        html, cids = self.render(
-            html, 
-            images=images,
-            domain=domain,
-            **kwargs
-        )
+        if self.use_jinja:
+            domain = parseaddr(msg["from"])[1].split("@")[-1] if self.domain is None else self.domain
+            html, cids = self.render(
+                html, 
+                images=images,
+                domain=domain,
+                **kwargs
+            )
         msg.add_alternative(html, subtype='html')
         msg.add_alternative(html, subtype='html')
 
 
-        if images is not None:
+        if self.use_jinja and images is not None:
             # https://stackoverflow.com/a/49098251/13696660
             # https://stackoverflow.com/a/49098251/13696660
             html_msg = msg.get_payload()[-1]
             html_msg = msg.get_payload()[-1]
             cid_path_mapping = {cids[name]: path for name, path in images.items()}
             cid_path_mapping = {cids[name]: path for name, path in images.items()}

+ 13 - 1
redmail/email/sender.py

@@ -76,6 +76,10 @@ class EmailSender:
     html_template : str
     html_template : str
         Name of the template to use as the HTML body of emails 
         Name of the template to use as the HTML body of emails 
         if not specified in the send method.
         if not specified in the send method.
+    use_jinja : bool
+        Use Jinja to render text/HTML. If Jinja is disabled,
+        images cannot be embedded to HTML, templates have no
+        effect and body_params are not used. Defaults True
     templates_html : jinja2.Environment
     templates_html : jinja2.Environment
         Jinja environment used for loading HTML templates
         Jinja environment used for loading HTML templates
         if ``html_template`` is specified in send.
         if ``html_template`` is specified in send.
@@ -150,6 +154,7 @@ class EmailSender:
         self.html = None
         self.html = None
         self.html_template = None
         self.html_template = None
         self.text_template = None
         self.text_template = None
+        self.use_jinja = True
 
 
         self.use_starttls = use_starttls
         self.use_starttls = use_starttls
         self.cls_smtp = cls_smtp
         self.cls_smtp = cls_smtp
@@ -215,6 +220,9 @@ class EmailSender:
             DataFrames.
             DataFrames.
         body_params : dict, optional
         body_params : dict, optional
             Extra Jinja parameters passed to the HTML and text bodies.
             Extra Jinja parameters passed to the HTML and text bodies.
+        use_jinja : bool
+            Use Jinja to render text/HTML. If Jinja is disabled, body content cannot be 
+            embedded, templates have no effect and body parameters do nothing.
         attachments : dict, optional
         attachments : dict, optional
             Attachments of the email. If dict value is string, the attachment content
             Attachments of the email. If dict value is string, the attachment content
             is the string itself. If path, the attachment is the content of the path's file.
             is the string itself. If path, the attachment is the content of the path's file.
@@ -288,7 +296,8 @@ class EmailSender:
                   body_images:Optional[Dict[str, Union[str, bytes, 'plt.Figure', 'Image']]]=None, 
                   body_images:Optional[Dict[str, Union[str, bytes, 'plt.Figure', 'Image']]]=None, 
                   body_tables:Optional[Dict[str, 'pd.DataFrame']]=None, 
                   body_tables:Optional[Dict[str, 'pd.DataFrame']]=None, 
                   body_params:Optional[Dict[str, Any]]=None,
                   body_params:Optional[Dict[str, Any]]=None,
-                  attachments:Optional[Dict[str, Union[str, os.PathLike, 'pd.DataFrame', bytes]]]=None) -> EmailMessage:
+                  attachments:Optional[Dict[str, Union[str, os.PathLike, 'pd.DataFrame', bytes]]]=None,
+                  use_jinja=None) -> EmailMessage:
         """Get the email message"""
         """Get the email message"""
 
 
         subject = subject or self.subject
         subject = subject or self.subject
@@ -302,6 +311,7 @@ class EmailSender:
         text = text or self.text
         text = text or self.text
         html_template = html_template or self.html_template
         html_template = html_template or self.html_template
         text_template = text_template or self.text_template
         text_template = text_template or self.text_template
+        use_jinja = self.use_jinja if use_jinja is None else use_jinja
 
 
         if subject is None:
         if subject is None:
             raise ValueError("Email must have a subject")
             raise ValueError("Email must have a subject")
@@ -318,6 +328,7 @@ class EmailSender:
             body = TextBody(
             body = TextBody(
                 template=self.get_text_template(text_template),
                 template=self.get_text_template(text_template),
                 table_template=self.get_text_table_template(),
                 table_template=self.get_text_table_template(),
+                use_jinja=use_jinja
             )
             )
             body.attach(
             body.attach(
                 msg, 
                 msg, 
@@ -330,6 +341,7 @@ class EmailSender:
             body = HTMLBody(
             body = HTMLBody(
                 template=self.get_html_template(html_template),
                 template=self.get_html_template(html_template),
                 table_template=self.get_html_table_template(),
                 table_template=self.get_html_table_template(),
+                use_jinja=use_jinja
             )
             )
             body.attach(
             body.attach(
                 msg,
                 msg,

+ 30 - 0
redmail/test/email/test_body.py

@@ -138,6 +138,36 @@ def test_with_jinja_params(html, text, extra, expected_html, expected_text):
     assert expected_html == html
     assert expected_html == html
     assert expected_text == text
     assert expected_text == text
 
 
+@pytest.mark.parametrize("use_jinja_obj,use_jinja", [
+    pytest.param(None, False, id="Use arg"),
+    pytest.param(False, None, id="Use attr"),
+    pytest.param(True, False, id="Override"),
+])
+def test_without_jinja(use_jinja_obj, use_jinja):
+    html = "<h3>Hi,</h3> <p>This is {{ user }} from { node }. I'm really {{ sender.full_name }}.</p>"
+    expected_html = "<h3>Hi,</h3> <p>This is {{ user }} from { node }. I'm really {{ sender.full_name }}.</p>\n"
+    text = "Hi, \nThis is {{ user }} from { node }. I'm really {{ sender.full_name }}."
+    expected_text = "Hi, \nThis is {{ user }} from { node }. I'm really {{ sender.full_name }}.\n"
+
+    sender = EmailSender(host=None, port=1234)
+    sender.use_jinja = use_jinja_obj
+    msg = sender.get_message(
+        sender="me@example.com",
+        receivers="you@example.com",
+        subject="Some news",
+        text=text,
+        html=html,
+        use_jinja=use_jinja,
+    )
+    
+    assert "multipart/alternative" == msg.get_content_type()
+
+    text = remove_email_extra(msg.get_payload()[0].get_payload())
+    html = remove_email_extra(msg.get_payload()[1].get_payload())
+
+    assert expected_html == html
+    assert expected_text == text
+
 def test_with_error():
 def test_with_error():
     sender = EmailSender(host=None, port=1234)
     sender = EmailSender(host=None, port=1234)
     try:
     try: