1
0
Mikael Koli 4 жил өмнө
parent
commit
e93993c8e7

BIN
docs/imgs/email_emb_img.png


BIN
docs/imgs/email_emb_plt.png


+ 6 - 1
docs/index.rst

@@ -158,7 +158,12 @@ There is much more to offer. Install the package:
 
 
     pip install redmail
     pip install redmail
 
 
-and read further.
+and read further. Here are some example use cases:
+
+- :ref:`cookbook-campaign`
+- :ref:`cookbook-alerts`
+- :ref:`cookbook-stats`
+- :ref:`examples-mega`
 
 
 .. toctree::
 .. toctree::
    :maxdepth: 2
    :maxdepth: 2

+ 66 - 9
docs/tutorials/body_content.rst

@@ -23,19 +23,19 @@ or styling in general. Here is a comparison
 of using ``df.to_html()`` directly vs embedding
 of using ``df.to_html()`` directly vs embedding
 via Red Mail:
 via Red Mail:
 
 
-|pic1| -- |pic2|
+|pic1| vs |pic2|
 
 
-.. |pic1| image:: /imgs/table_unrendered.png
+.. |pic1| image:: /imgs/table_without_style.png
    :height: 150px
    :height: 150px
    :align: top
    :align: top
    
    
 
 
-.. |pic2| image:: /imgs/table_rendered.png
+.. |pic2| image:: /imgs/table_with_style.png
    :height: 150px
    :height: 150px
    :align: top
    :align: top
 
 
 
 
-To embed tables, you can si  mply pass them 
+To embed tables, you can simply pass them 
 to the send function as Pandas dataframes:
 to the send function as Pandas dataframes:
 
 
 .. code-block:: python
 .. code-block:: python
@@ -68,7 +68,23 @@ well CSS.
     dataframe strucutres (empty, multi-indexed etc.) but
     dataframe strucutres (empty, multi-indexed etc.) but
     sometimes the rendering may be off if the dataframe
     sometimes the rendering may be off if the dataframe
     is especially complex in structural sense. There are
     is especially complex in structural sense. There are
-    development plans to make it even more better.
+    plans to make it even more better.
+
+You may also override the template paths (see 
+:ref:`templating`) to create custom templates
+if you wish to make your own table prettifying:
+
+.. code-block:: python
+
+    email.set_template_paths(
+        html_table="path/to/templates", 
+        text_template="path/to/templates"
+    )
+    email.default_html_theme = "my_table_template.html"
+    email.default_text_theme = "my_table_template.txt"
+
+The templates get parameter ``df`` which is the dataframe
+to be prettified.
 
 
 .. _embedding-images:
 .. _embedding-images:
 
 
@@ -83,12 +99,19 @@ of the email:
     email.send(
     email.send(
         subject='Some attachments',
         subject='Some attachments',
         receivers=['first.last@example.com'],
         receivers=['first.last@example.com'],
-        html="<h1>This is an image:</h1> {{ myimage }}",
+        html="""<h1>This is an image:</h1> 
+                {{ my_image }}
+        """,
         body_images={
         body_images={
-            'myimage': 'path/to/image.png', 
+            'my_image': 'path/to/image.png', 
         }
         }
     )
     )
 
 
+The outcome looks like this:
+
+.. image:: /imgs/email_emb_img.png
+    :align: center
+
 The image will be rendered as ``<img src="cid:...">``.
 The image will be rendered as ``<img src="cid:...">``.
 In case you need to control the image (like the size)
 In case you need to control the image (like the size)
 you can also create the ``img`` tag yourself:
 you can also create the ``img`` tag yourself:
@@ -98,9 +121,9 @@ you can also create the ``img`` tag yourself:
     email.send(
     email.send(
         subject='Some attachments',
         subject='Some attachments',
         receivers=['first.last@example.com'],
         receivers=['first.last@example.com'],
-        html='<h1>This is an image:</h1> <img src="{{ myimage.src }}">',
+        html='<h1>This is an image:</h1> <img src="{{ my_image.src }}" width=500 height=350>',
         body_images={
         body_images={
-            'myimage': 'path/to/image.png', 
+            'my_image': 'path/to/image.png', 
         }
         }
     )
     )
 
 
@@ -110,3 +133,37 @@ In addition to paths as strings, the following are supported:
 - ``bytes`` (the image as raw bytes)
 - ``bytes`` (the image as raw bytes)
 - ``matplotlib.pyplot.Figure``
 - ``matplotlib.pyplot.Figure``
 - ``PIL.Image``
 - ``PIL.Image``
+
+.. _embedding-plt:
+
+Embedding Figure
+^^^^^^^^^^^^^^^^
+
+As mentioned, you may also include Matplotlib figures directly to the email.
+This is especially handy if you are creating automatic statistics.
+
+A simple example to include a figure:
+
+.. code-block:: python
+
+    # Create a simple plot
+    import matplotlib.pyplot as plt
+    fig = plt.figure()
+    plt.plot([1,2,3,2,3])
+
+    # Send the plot
+    email.send(
+        subject='Some attachments',
+        receivers=['first.last@example.com'],
+        html="""<h1>This is a plot:</h1> 
+                {{ my_plot }}
+        """,
+        body_images={
+            'my_plot': fig, 
+        }
+    )
+
+The outcome looks like this:
+
+.. image:: /imgs/email_emb_plt.png
+    :align: center

+ 37 - 0
docs/tutorials/config.rst

@@ -0,0 +1,37 @@
+
+Configuring for Different Providers
+===================================
+
+.. _config-gmail:
+
+Gmail
+-----
+
+You need to make an application password `see this Google's answer <https://support.google.com/accounts/answer/185833>`_.
+You may also need to set up `2-step verification <https://support.google.com/accounts/answer/185839>`_ in order to
+be able to create an application password. Don't worry, those are easy things to configure.
+
+When you have your application password you can use Red Mail's gmail object that has the Gmail
+server pre-configured:
+
+.. code-block:: python
+
+    from redmail import gmail
+    gmail.user_name = 'example@gmail.com' # Your Gmail address
+    gmail.password = '<APP PASSWORD>'
+
+    # And then you can send emails
+    gmail.send(
+        subject="Example email",
+        receivers=['example@gmail.com']
+        text="Hi, this is an email."
+    )
+
+.. note::
+
+    You can only send emails using your Gmail email address. Changing ``sender`` has no effect.
+
+.. note::
+
+    ``gmail`` is actually nothing more than an instance of :class:`redmail.EmailSender`
+    with ``smtp.gmail.com`` as the host and ``587`` as the port.

+ 111 - 21
docs/tutorials/cookbook.rst

@@ -1,35 +1,65 @@
 .. _cookbook:
 .. _cookbook:
 
 
-Cook Book
+Cookbook
 =========
 =========
 
 
-This section provides various handy tips.
+This section provides various examples for various 
+needs.
 
 
-.. _config-gmail:
 
 
-Gmail
------
+.. _cookbook-campaign:
 
 
-You need to make an app password `see this Google's answer <https://support.google.com/accounts/answer/185833>`_. 
-When that is done you can use Red Mail's gmail object that has the Gmail
-server pre-configured:
+Email Campaign
+--------------
 
 
-.. code-block:: python
+In case you have a list of clients or customers you 
+wish to send personalized emails, you may benefit from
+templating. It may help to make the templates to an HTML
+file, polish them and after then send:
 
 
-    from redmail import gmail
-    gmail.user_name = 'example@gmail.com' # Your Gmail user
-    gmail.password = '<APP PASSWORD>'
+.. code-block:: python
 
 
-    # And then you can send emails
-    gmail.send(
-        subject="Example email",
-        receivers=['example@gmail.com']
-        text="Hi, this is an email."
+    from redmail import EmailSender
+    
+    email = EmailSender(...)
+    email.receivers = ['we@example.com']
+    email.set_template_paths(
+        html="path/to/campaigns"
     )
     )
 
 
-.. note::
+Then make a HTML file, for example ``path/to/campaigns/summer_sale.html``:
+
+.. code-block:: html
+
+    <h1>Thank you, {{ customer }}, for being awesome!</h1>
+    <p>
+        We are pleased to inform you that we have a lot of products
+        in huge discounts.
+    </p>
+    <ul>
+    {% for product, discount, in discounts.items() %}
+        <li>{{ product }}: {{ '{:.0f} %'.format(discount * 100) }}</li>
+    {% endfor %}
+    </ul>
+    <p>Kind regards, We Ltd.</p>
 
 
-    You can only send emails using your Gmail email address. Changing ``sender`` has no effect.
+Finally send the emails:
+
+.. code-block:: python
+
+    discounts = {'shoes': 0.2, 'shirts': 0.4}
+    customers = ['cust1@example.com', 'cust2@example.com', ...]
+    for customer in customers:
+        email.send(
+            subject="Summer Sale!",
+            html_template="summer_sale.html",
+            body_params={
+                "customer": customer,
+                "discounts": discounts
+            }
+        )
+
+.. _cookbook-alerts:
 
 
 Error Alerts
 Error Alerts
 ------------
 ------------
@@ -42,11 +72,71 @@ templated error alerts that include the full traceback:
     from redmail import EmailSender
     from redmail import EmailSender
     
     
     error_email = EmailSender(...)
     error_email = EmailSender(...)
+    error_email.sender = 'me@example.com'
     error_email.receivers = ['me@example.com']
     error_email.receivers = ['me@example.com']
-    error_email.html = """<h2>An error encountered</h2>{{ error }}"""
+    error_email.html = """
+        <h2>An error encountered</h2>
+        {{ error }}
+    """
 
 
     try:
     try:
         raise RuntimeError("Oops")
         raise RuntimeError("Oops")
     except:
     except:
         # Send an email including the traceback
         # Send an email including the traceback
-        error_email.send(subject="Fail: doing stuff failed")
+        error_email.send(subject="Fail: doing stuff failed")
+
+.. note::
+
+    The ``error`` formatting object identifies which body it is being
+    attached to. If you wish to use text body, ``error`` will show up
+    similarly as Python errors you see on terminals. See more from
+    :class:`redmail.models.Error`
+
+.. _cookbook-stats:
+
+Stats Reports
+-------------
+
+As demonstrated :ref:`here <embedding-plt>`, embedding Matplotlib 
+figures to the HTML bodies is trivial. Therefore you can easily
+create diagnostic reports or automatic analyses. Just create 
+the plots and let Red Mail send them to you:
+
+.. code-block:: python
+
+    from redmail import EmailSender
+    
+    stats_report = EmailSender(...)
+    stats_report.sender = 'no-reply@example.com'
+    stats_report.receivers = ['me@example.com']
+
+    # Create a plot
+    import matplotlib.pyplot as plt
+    fig_performance = plt.Figure()
+    plt.plot([1,2,3,2,3])
+
+    # Create summary table
+    import pandas as pd
+    df = pd.DataFrame(...)
+    df_summary = df.describe()
+
+    # Send the report
+    stats_report.send(
+        subject="System Diagnostics",
+        html="""
+            <h1>System Diagnostics ({{ now }})</h1>
+            <hr>
+            <h2>Performance</h2>
+            {{ perf_plot }}
+            <h2>Summary Statistics</h2>
+            {{ tbl_summary }}
+            <hr>
+            <p>System running on {{ node }}</p>
+        """,
+        body_images={
+            "perf_plot": fig_performance,
+        },
+        body_tables={
+            "tbl_summary": df_summary
+        }
+    )

+ 115 - 0
docs/tutorials/example.rst

@@ -0,0 +1,115 @@
+
+.. _examples-simple:
+
+Examples
+========
+
+Simple Example
+--------------
+
+.. code-block:: python
+
+    from redmail import EmailSender
+
+    email = EmailSender(
+        host='localhost', 
+        port=0, 
+        user_name='me@example.com', 
+        password='<PASSWORD>'
+    )
+    email.send(
+        subject="An email",
+        sender="me@example.com",
+        receivers=['you@example.com'],
+        test="Hi, this is an email.",
+        html="<h1>Hi, </h1><p>this is an email.</p>"
+    )
+
+.. _examples-mega:
+
+Super Example
+-------------
+
+This example covers the most interesting 
+features of Red Mail:
+
+.. code-block:: python
+
+    from pathlib import Path
+    from redmail import EmailSender
+
+    import pandas as pd
+    from PIL import Image
+    import matplotlib.pyplot as plt
+
+    fig = plt.figure()
+    plt.plot([1, 2, 3])
+
+    df = pd.DataFrame({"A": [1, 2, 3], "B": [1, 2, 3]})
+
+    byte_content = Path("a_file.bin").read_bytes()
+
+    email = EmailSender(
+        host='localhost', 
+        port=0, 
+        user_name='me@example.com', 
+        password='<PASSWORD>'
+    )
+
+    # Send an email
+    email.send(
+        subject="A lot of stuff!",
+        sender="me@example.com",
+
+        # Receivers
+        receivers=["you@example.com"],
+        cc=['also@example.com'],
+        bcc=['external@example.com'],
+
+        # Bodies
+        text="""Hi {{ friend }},
+        This email has a lot of stuff!
+        Use HTML to view the awesome content.
+        """,
+        html="""<h1>Hi {{ friend }},</h1>
+        <p>This email has a lot of stuff!</p>
+        <p>Like this image:</p>
+        {{ my_image }}
+        <p>or this image:</p>
+        {{ my_pillow }}
+        <p>or this plot:</p>
+        {{ my_plot }}
+        <p>or this table:</p>
+        {{ my_table }}
+        <p>or this loop:</p>
+        <ul>
+        {% for value in container %}
+            {% if value > 5 %}
+                <li>{{ value }}</li>
+            {% else %}
+                <li style="color: red">{{ value }}</li>
+            {% endif %}
+        {% endfor %}
+        </ul>
+        """,
+
+        # Embedded content
+        body_images={
+            "my_image": "path/to/image.png",
+            "my_pillow": Image.new('RGB', (100, 30), color = (73, 109, 137))
+            "my_plot": fig,
+        },
+        body_tables={
+            "my_table": df,
+        },
+        body_params={
+            "friend": "Jack",
+            "container": [1, 3, 5, 7, 9],
+        },
+        attachments={
+            "data.csv": df,
+            "file.txt": "This is file content",
+            "file.html": Path("path/to/a_file.html"),
+            "file.bin": byte_content,
+        }
+    )

+ 10 - 11
docs/tutorials/getting_started.rst

@@ -16,7 +16,6 @@ Configuring Email
 
 
 You can configure your sender by:
 You can configure your sender by:
 
 
-
 .. code-block:: python
 .. code-block:: python
 
 
    from redmail import EmailSender
    from redmail import EmailSender
@@ -28,18 +27,17 @@ You can configure your sender by:
        password='<PASSWORD>'
        password='<PASSWORD>'
    )
    )
 
 
-If your SMTP server does not require login to send emails then 
-just don't pass ``user_name`` and ``password`` to ``EmailSender``.
-
-Alternatively, if you use Gmail there is a pre-configured sender
-which you can just import and set user name and password:
-
 .. code-block:: python
 .. code-block:: python
 
 
-   from redmail import gmail
+   # Or if your SMTP server does not require credentials
+   email = EmailSender(
+       host='<SMTP HOST>',
+       port='<SMTP PORT>',
+   )
+
+Alternatively, there is a pre-configured sender for Gmail. 
+Please see :ref:`how to configure Gmail <config-gmail>` for more.
 
 
-   gmail.user_name = 'me@gmail.com'
-   gmail.password = '<PASSWORD>'
 
 
 Sending Emails
 Sending Emails
 --------------
 --------------
@@ -50,7 +48,8 @@ You can just send emails by calling the method ``send``:
 
 
    email.send(
    email.send(
        subject='email subject',
        subject='email subject',
-       receivers=['first.last@example.com'],
+       sender="me@example.com",
+       receivers=['you@example.com'],
        text="Hi, this is an email."
        text="Hi, this is an email."
    )
    )
 
 

+ 15 - 2
docs/tutorials/index.rst

@@ -5,6 +5,18 @@ Tutorials
 
 
 Welcome to Red Mail's tutorials!
 Welcome to Red Mail's tutorials!
 
 
+See:
+
+- :ref:`This to learn how to configure and get started <getting-started>`
+- :ref:`This to send with text and HTML bodies <sending-emails>`
+- :ref:`This to send with attachments <attachments>`
+- :ref:`This to send with embedded content (in HTML) <embedded>`
+- :ref:`This to send with dynamic HTML (Jinja) <jinja-support>`
+- :ref:`This to send using HTML templates (Jinja) <templating>`
+- :ref:`This to configure Red Mail to various SMTP providers (ie. Gmail) <templating>`
+
+And see - :ref:`cookbook <cookbook>` for example use cases.
+
 .. toctree::
 .. toctree::
    :maxdepth: 1
    :maxdepth: 1
    :caption: Contents:
    :caption: Contents:
@@ -12,8 +24,9 @@ Welcome to Red Mail's tutorials!
    getting_started
    getting_started
    sending
    sending
    attachments
    attachments
-   jinja_support
    body_content
    body_content
+   jinja_support
    templating
    templating
    cookbook
    cookbook
-
+   config
+   example

+ 1 - 1
docs/tutorials/jinja_support.rst

@@ -65,7 +65,7 @@ some of them:
 Here is a list of default parameters:
 Here is a list of default parameters:
 
 
 ================ ==================================== =========================================================
 ================ ==================================== =========================================================
-Parameter Name   Class                                Description
+Parameter Name   Type                                 Description
 ================ ==================================== =========================================================
 ================ ==================================== =========================================================
 sender           :class:`redmail.models.EmailAddress` Format class of the email sender
 sender           :class:`redmail.models.EmailAddress` Format class of the email sender
 error            :class:`redmail.models.Error`        Format class of the current exception (if any)
 error            :class:`redmail.models.Error`        Format class of the current exception (if any)

+ 33 - 5
docs/tutorials/sending.rst

@@ -4,8 +4,32 @@ Sending Emails
 ==============
 ==============
 
 
 This section covers the basics of sending emails.
 This section covers the basics of sending emails.
-We use an ``EmailSender`` configured in :ref:`configure`.
+See :ref:`configure` to revise how ``EmailSender``
+is configured. At minimum, sending an email requires:
 
 
+.. code-block:: python
+
+    from email import EmailSender
+    email = EmailSender(host='localhost', port=0)
+
+    email.send(
+        subject='email subject',
+        sender="me@example.com",
+        receivers=['you@example.com']
+    )
+
+.. note::
+
+    If you don't spesify the ``sender``, the sender is considered to 
+    be ``email.sender``. If ``email.sender`` is also missing, the sender
+    is then set to be ``email.user_name``. Ensure that any of these is a 
+    valid email address. 
+
+.. note::
+
+    Some email providers (such as Gmail) do not allow specifying
+    sender. For example, Gmail will outright ignore it and always
+    use your own email address.
 
 
 Sending Email with Text Body
 Sending Email with Text Body
 ----------------------------
 ----------------------------
@@ -16,7 +40,8 @@ To send an email with plain text message:
 
 
    email.send(
    email.send(
        subject='email subject',
        subject='email subject',
-       receivers=['first.last@example.com'],
+       sender="me@example.com",
+       receivers=['you@example.com'],
        text="Hi, this is an email."
        text="Hi, this is an email."
    )
    )
 
 
@@ -29,7 +54,8 @@ To send an email with html content:
 
 
     email.send(
     email.send(
         subject='email subject',
         subject='email subject',
-        receivers=['first.last@example.com'],
+        sender="me@example.com",
+        receivers=['you@example.com'],
         html="""
         html="""
             <h1>Hi,</h1>
             <h1>Hi,</h1>
             <p>this is an email.</p>
             <p>this is an email.</p>
@@ -46,7 +72,8 @@ You can also include both to your email:
 
 
     email.send(
     email.send(
         subject='email subject',
         subject='email subject',
-        receivers=['first.last@example.com'],
+        sender="me@example.com",
+        receivers=['you@example.com'],
         text="Hi, this is an email.",
         text="Hi, this is an email.",
         html="""
         html="""
             <h1>Hi,</h1>
             <h1>Hi,</h1>
@@ -66,7 +93,8 @@ to your emails:
 
 
     email.send(
     email.send(
         subject='email subject',
         subject='email subject',
-        receivers=['first.last@example.com'],
+        sender="me@example.com",
+        receivers=['you@example.com'],
         cc=['also@example.com'],
         cc=['also@example.com'],
         bcc=['outsider@example.com']
         bcc=['outsider@example.com']
     )
     )

+ 8 - 1
docs/tutorials/templating.rst

@@ -21,7 +21,14 @@ template path to a custom folder and
     If you are dissatisfied with default HTML and text
     If you are dissatisfied with default HTML and text
     table templates, you can also pass ``html_table``
     table templates, you can also pass ``html_table``
     and ``text_table`` to specify the templates used
     and ``text_table`` to specify the templates used
-    to render embedded tables.
+    to render embedded tables:
+
+    .. code-block:: python
+
+        email.set_template_paths(
+            html_table="path/html/tables",
+            text_table="path/text/tables",
+        )
 
 
 Next we will make a simple template, let's call it 
 Next we will make a simple template, let's call it 
 ``event_card.html``:
 ``event_card.html``: