Explorar o código

add: use_jinja to disable Jinja

Mikael Koli %!s(int64=3) %!d(string=hai) anos
pai
achega
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/>`_ 
-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:
 
-    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.table_template = table_template
+        self.use_jinja = use_jinja
 
     def render_body(self, body:str, jinja_params:dict):
         if body is not None and self.template is not None:
@@ -79,7 +80,8 @@ class Body:
 class TextBody(Body):
 
     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)
 
 
@@ -109,16 +111,17 @@ class HTMLBody(Body):
             jinja_params : dict
                 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')
 
-        if images is not None:
+        if self.use_jinja and images is not None:
             # https://stackoverflow.com/a/49098251/13696660
             html_msg = msg.get_payload()[-1]
             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
         Name of the template to use as the HTML body of emails 
         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
         Jinja environment used for loading HTML templates
         if ``html_template`` is specified in send.
@@ -150,6 +154,7 @@ class EmailSender:
         self.html = None
         self.html_template = None
         self.text_template = None
+        self.use_jinja = True
 
         self.use_starttls = use_starttls
         self.cls_smtp = cls_smtp
@@ -215,6 +220,9 @@ class EmailSender:
             DataFrames.
         body_params : dict, optional
             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 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.
@@ -288,7 +296,8 @@ class EmailSender:
                   body_images:Optional[Dict[str, Union[str, bytes, 'plt.Figure', 'Image']]]=None, 
                   body_tables:Optional[Dict[str, 'pd.DataFrame']]=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"""
 
         subject = subject or self.subject
@@ -302,6 +311,7 @@ class EmailSender:
         text = text or self.text
         html_template = html_template or self.html_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:
             raise ValueError("Email must have a subject")
@@ -318,6 +328,7 @@ class EmailSender:
             body = TextBody(
                 template=self.get_text_template(text_template),
                 table_template=self.get_text_table_template(),
+                use_jinja=use_jinja
             )
             body.attach(
                 msg, 
@@ -330,6 +341,7 @@ class EmailSender:
             body = HTMLBody(
                 template=self.get_html_template(html_template),
                 table_template=self.get_html_table_template(),
+                use_jinja=use_jinja
             )
             body.attach(
                 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_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():
     sender = EmailSender(host=None, port=1234)
     try: