From 4b21fa687d1f0be3fb05227df27f4c3dde234cb0 Mon Sep 17 00:00:00 2001 From: Jules <54960783+juleswg23@users.noreply.github.com> Date: Fri, 7 Nov 2025 10:49:33 -0500 Subject: [PATCH 1/4] rename to nbmail --- .github/workflows/ci.yml | 14 +- Makefile | 6 +- README.md | 14 +- docs/_quarto.yml | 4 +- docs/objects.json | 2 +- docs/summary.quarto_ipynb | 251 ++++++++++++++++++ examples/.gitignore | 2 +- examples/emailer_lib.qmd | 0 {emailer_lib => nbmail}/__init__.py | 0 {emailer_lib => nbmail}/egress.py | 0 {emailer_lib => nbmail}/ingress.py | 0 {emailer_lib => nbmail}/mjml/.gitignore | 0 {emailer_lib => nbmail}/mjml/README.md | 14 +- {emailer_lib => nbmail}/mjml/__init__.py | 0 {emailer_lib => nbmail}/mjml/_core.py | 0 .../mjml/image_processor.py | 4 +- .../mjml/scripts/generate_tags.py | 6 +- {emailer_lib => nbmail}/mjml/tags.py | 70 ++--- .../mjml/tests/test_core.py | 4 +- .../mjml/tests/test_image_processor.py | 4 +- .../mjml/tests/test_tags.py | 2 +- {emailer_lib => nbmail}/structs.py | 0 .../tests/__snapshots__/test_structs.ambr | 0 {emailer_lib => nbmail}/tests/test_egress.py | 16 +- .../tests/test_end_to_end.py | 6 +- {emailer_lib => nbmail}/tests/test_ingress.py | 8 +- {emailer_lib => nbmail}/tests/test_structs.py | 2 +- {emailer_lib => nbmail}/tests/test_utils.py | 2 +- {emailer_lib => nbmail}/utils.py | 0 pyproject.toml | 10 +- uv.lock | 2 +- 31 files changed, 347 insertions(+), 96 deletions(-) create mode 100644 docs/summary.quarto_ipynb create mode 100644 examples/emailer_lib.qmd rename {emailer_lib => nbmail}/__init__.py (100%) rename {emailer_lib => nbmail}/egress.py (100%) rename {emailer_lib => nbmail}/ingress.py (100%) rename {emailer_lib => nbmail}/mjml/.gitignore (100%) rename {emailer_lib => nbmail}/mjml/README.md (91%) rename {emailer_lib => nbmail}/mjml/__init__.py (100%) rename {emailer_lib => nbmail}/mjml/_core.py (100%) rename {emailer_lib => nbmail}/mjml/image_processor.py (97%) rename {emailer_lib => nbmail}/mjml/scripts/generate_tags.py (96%) rename {emailer_lib => nbmail}/mjml/tags.py (94%) rename {emailer_lib => nbmail}/mjml/tests/test_core.py (98%) rename {emailer_lib => nbmail}/mjml/tests/test_image_processor.py (97%) rename {emailer_lib => nbmail}/mjml/tests/test_tags.py (99%) rename {emailer_lib => nbmail}/structs.py (100%) rename {emailer_lib => nbmail}/tests/__snapshots__/test_structs.ambr (100%) rename {emailer_lib => nbmail}/tests/test_egress.py (94%) rename {emailer_lib => nbmail}/tests/test_end_to_end.py (93%) rename {emailer_lib => nbmail}/tests/test_ingress.py (97%) rename {emailer_lib => nbmail}/tests/test_structs.py (99%) rename {emailer_lib => nbmail}/tests/test_utils.py (99%) rename {emailer_lib => nbmail}/utils.py (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6115fc1..814cde2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: - name: Install the project run: uv sync --all-extras --dev - - name: Install emailer-lib + - name: Install nbmail run: uv pip install -e . # quarto docs build ---- @@ -57,7 +57,7 @@ jobs: with: source-dir: docs/_site - test-emailer-lib: + test-nbmail: runs-on: ubuntu-latest strategy: matrix: @@ -80,19 +80,19 @@ jobs: - name: Install the project run: uv sync --all-extras --dev - - name: Install emailer-lib + - name: Install nbmail run: uv pip install -e . - name: Install the project deps run: uv pip install -e .[dev] - - name: Test emailer-lib + - name: Test nbmail run: | - uv run pytest emailer_lib/tests/ --cov=emailer_lib --cov-report=xml --cov-report=term-missing + uv run pytest nbmail/tests/ --cov=nbmail --cov-report=xml --cov-report=term-missing - name: Upload coverage reports uses: codecov/codecov-action@v4 if: ${{ matrix.python-version == '3.12' }} with: - file: emailer-lib/coverage.xml - flags: emailer-lib + file: nbmail/coverage.xml + flags: nbmail diff --git a/Makefile b/Makefile index c0c4950..b743416 100644 --- a/Makefile +++ b/Makefile @@ -5,10 +5,10 @@ preview: cd docs && quarto preview test: - pytest emailer_lib/tests emailer_lib/mjml/tests --cov-report=xml + pytest nbmail/tests nbmail/mjml/tests --cov-report=xml test-update: - pytest emailer_lib/tests emailer_lib/mjml/tests --snapshot-update + pytest nbmail/tests nbmail/mjml/tests --snapshot-update generate-mjml-tags: - python3 emailer_lib/mjml/scripts/generate_tags.py + python3 nbmail/mjml/scripts/generate_tags.py diff --git a/README.md b/README.md index b026ae7..d4b19dc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# emailer-lib +# nbmail @@ -11,12 +11,12 @@ -> ⚠️ **emailer-lib is currently in development, expect breaking changes.** +> ⚠️ **nbmail is currently in development, expect breaking changes.** -### What is [emailer-lib](https://posit-dev.github.io/email-for-data-science/reference/)? +### What is [nbmail](https://posit-dev.github.io/email-for-data-science/reference/)? -**emailer-lib** is a Python package for serializing, previewing, and sending email messages in a consistent, simple structure. It provides utilities to convert emails from different sources (Redmail, Yagmail, MJML, Quarto JSON) into a unified intermediate format, and send them via multiple backends (Gmail, SMTP, Mailgun, etc.). +**nbmail** is a Python package for serializing, previewing, and sending email messages in a consistent, simple structure. It provides utilities to convert emails from different sources (Redmail, Yagmail, MJML, Quarto JSON) into a unified intermediate format, and send them via multiple backends (Gmail, SMTP, Mailgun, etc.). The package is designed for data science workflows and Quarto projects, making it easy to generate, preview, and deliver rich email content programmatically. @@ -24,14 +24,14 @@ The package is designed for data science workflows and Quarto projects, making i Install the latest release from your local repo or PyPI: ```bash -pip install -e ./emailer-lib +pip install -e ./nbmail ``` --> ## Example Usage ```python -from emailer_lib import ( +from nbmail import ( quarto_json_to_intermediate_email, IntermediateEmail, send_intermediate_email_with_gmail, @@ -81,4 +81,4 @@ url = {https://github.com/posit-dev/gt-extras}, version = {0.0.1} } ``` --> -For more information, see the [docs](https://posit-dev.github.io/email-for-data-science/reference) or [open an issue](https://github.com/posit-dev/email-for-data-science/issues) with questions or suggestions! \ No newline at end of file +For more information, see the [docs](https://posit-dev.github.io/email-for-data-science/reference) or [open an issue](https://github.com/posit-dev/email-for-data-science/issues) with questions or suggestions! diff --git a/docs/_quarto.yml b/docs/_quarto.yml index cfa6598..78f67c8 100644 --- a/docs/_quarto.yml +++ b/docs/_quarto.yml @@ -29,7 +29,7 @@ website: - orchestrating-tests.qmd quartodoc: - package: emailer_lib + package: nbmail dir: reference title: API Reference css: reference/_styles-quartodoc.css @@ -79,7 +79,7 @@ quartodoc: - title: MJML Authoring desc: > Write responsive emails with MJML - package: emailer_lib + package: nbmail contents: - mjml.mjml - mjml.head diff --git a/docs/objects.json b/docs/objects.json index 6165209..fa4a566 100644 --- a/docs/objects.json +++ b/docs/objects.json @@ -1 +1 @@ -{"project": "emailer_lib", "version": "0.0.9999", "count": 106, "items": [{"name": "emailer_lib.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/emailer_lib.IntermediateEmail.preview_send_email.html#emailer_lib.IntermediateEmail.preview_send_email", "dispname": "-"}, {"name": "emailer_lib.structs.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/emailer_lib.IntermediateEmail.preview_send_email.html#emailer_lib.IntermediateEmail.preview_send_email", "dispname": "emailer_lib.IntermediateEmail.preview_send_email"}, {"name": "emailer_lib.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/emailer_lib.IntermediateEmail.write_email_message.html#emailer_lib.IntermediateEmail.write_email_message", "dispname": "-"}, {"name": "emailer_lib.structs.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/emailer_lib.IntermediateEmail.write_email_message.html#emailer_lib.IntermediateEmail.write_email_message", "dispname": "emailer_lib.IntermediateEmail.write_email_message"}, {"name": "emailer_lib.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/emailer_lib.IntermediateEmail.write_preview_email.html#emailer_lib.IntermediateEmail.write_preview_email", "dispname": "-"}, {"name": "emailer_lib.structs.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/emailer_lib.IntermediateEmail.write_preview_email.html#emailer_lib.IntermediateEmail.write_preview_email", "dispname": "emailer_lib.IntermediateEmail.write_preview_email"}, {"name": "emailer_lib.IntermediateEmail", "domain": "py", "role": "class", "priority": "1", "uri": "reference/IntermediateEmail.html#emailer_lib.IntermediateEmail", "dispname": "-"}, {"name": "emailer_lib.structs.IntermediateEmail", "domain": "py", "role": "class", "priority": "1", "uri": "reference/IntermediateEmail.html#emailer_lib.IntermediateEmail", "dispname": "emailer_lib.IntermediateEmail"}, {"name": "emailer_lib.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_preview_email.html#emailer_lib.IntermediateEmail.write_preview_email", "dispname": "-"}, {"name": "emailer_lib.structs.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_preview_email.html#emailer_lib.IntermediateEmail.write_preview_email", "dispname": "emailer_lib.IntermediateEmail.write_preview_email"}, {"name": "emailer_lib.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_email_message.html#emailer_lib.IntermediateEmail.write_email_message", "dispname": "-"}, {"name": "emailer_lib.structs.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_email_message.html#emailer_lib.IntermediateEmail.write_email_message", "dispname": "emailer_lib.IntermediateEmail.write_email_message"}, {"name": "emailer_lib.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.preview_send_email.html#emailer_lib.IntermediateEmail.preview_send_email", "dispname": "-"}, {"name": "emailer_lib.structs.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.preview_send_email.html#emailer_lib.IntermediateEmail.preview_send_email", "dispname": "emailer_lib.IntermediateEmail.preview_send_email"}, {"name": "emailer_lib.quarto_json_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/quarto_json_to_intermediate_email.html#emailer_lib.quarto_json_to_intermediate_email", "dispname": "-"}, {"name": "emailer_lib.ingress.quarto_json_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/quarto_json_to_intermediate_email.html#emailer_lib.quarto_json_to_intermediate_email", "dispname": "emailer_lib.quarto_json_to_intermediate_email"}, {"name": "emailer_lib.mjml_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml_to_intermediate_email.html#emailer_lib.mjml_to_intermediate_email", "dispname": "-"}, {"name": "emailer_lib.ingress.mjml_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml_to_intermediate_email.html#emailer_lib.mjml_to_intermediate_email", "dispname": "emailer_lib.mjml_to_intermediate_email"}, {"name": "emailer_lib.redmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/redmail_to_intermediate_email.html#emailer_lib.redmail_to_intermediate_email", "dispname": "-"}, {"name": "emailer_lib.ingress.redmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/redmail_to_intermediate_email.html#emailer_lib.redmail_to_intermediate_email", "dispname": "emailer_lib.redmail_to_intermediate_email"}, {"name": "emailer_lib.yagmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/yagmail_to_intermediate_email.html#emailer_lib.yagmail_to_intermediate_email", "dispname": "-"}, {"name": "emailer_lib.ingress.yagmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/yagmail_to_intermediate_email.html#emailer_lib.yagmail_to_intermediate_email", "dispname": "emailer_lib.yagmail_to_intermediate_email"}, {"name": "emailer_lib.send_intermediate_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_gmail.html#emailer_lib.send_intermediate_email_with_gmail", "dispname": "-"}, {"name": "emailer_lib.egress.send_intermediate_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_gmail.html#emailer_lib.send_intermediate_email_with_gmail", "dispname": "emailer_lib.send_intermediate_email_with_gmail"}, {"name": "emailer_lib.send_intermediate_email_with_smtp", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_smtp.html#emailer_lib.send_intermediate_email_with_smtp", "dispname": "-"}, {"name": "emailer_lib.egress.send_intermediate_email_with_smtp", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_smtp.html#emailer_lib.send_intermediate_email_with_smtp", "dispname": "emailer_lib.send_intermediate_email_with_smtp"}, {"name": "emailer_lib.send_intermediate_email_with_redmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_redmail.html#emailer_lib.send_intermediate_email_with_redmail", "dispname": "-"}, {"name": "emailer_lib.egress.send_intermediate_email_with_redmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_redmail.html#emailer_lib.send_intermediate_email_with_redmail", "dispname": "emailer_lib.send_intermediate_email_with_redmail"}, {"name": "emailer_lib.send_intermediate_email_with_yagmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_yagmail.html#emailer_lib.send_intermediate_email_with_yagmail", "dispname": "-"}, {"name": "emailer_lib.egress.send_intermediate_email_with_yagmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_yagmail.html#emailer_lib.send_intermediate_email_with_yagmail", "dispname": "emailer_lib.send_intermediate_email_with_yagmail"}, {"name": "emailer_lib.send_intermediate_email_with_mailgun", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_mailgun.html#emailer_lib.send_intermediate_email_with_mailgun", "dispname": "-"}, {"name": "emailer_lib.egress.send_intermediate_email_with_mailgun", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_mailgun.html#emailer_lib.send_intermediate_email_with_mailgun", "dispname": "emailer_lib.send_intermediate_email_with_mailgun"}, {"name": "emailer_lib.send_quarto_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_quarto_email_with_gmail.html#emailer_lib.send_quarto_email_with_gmail", "dispname": "-"}, {"name": "emailer_lib.egress.send_quarto_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_quarto_email_with_gmail.html#emailer_lib.send_quarto_email_with_gmail", "dispname": "emailer_lib.send_quarto_email_with_gmail"}, {"name": "emailer_lib.write_email_message_to_file", "domain": "py", "role": "function", "priority": "1", "uri": "reference/write_email_message_to_file.html#emailer_lib.write_email_message_to_file", "dispname": "-"}, {"name": "emailer_lib.utils.write_email_message_to_file", "domain": "py", "role": "function", "priority": "1", "uri": "reference/write_email_message_to_file.html#emailer_lib.write_email_message_to_file", "dispname": "emailer_lib.write_email_message_to_file"}, {"name": "emailer_lib.mjml.mjml", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mjml.html#emailer_lib.mjml.mjml", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.mjml", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mjml.html#emailer_lib.mjml.mjml", "dispname": "emailer_lib.mjml.mjml"}, {"name": "emailer_lib.mjml.head", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.head.html#emailer_lib.mjml.head", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.head", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.head.html#emailer_lib.mjml.head", "dispname": "emailer_lib.mjml.head"}, {"name": "emailer_lib.mjml.body", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.body.html#emailer_lib.mjml.body", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.body", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.body.html#emailer_lib.mjml.body", "dispname": "emailer_lib.mjml.body"}, {"name": "emailer_lib.mjml.mj_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_attributes.html#emailer_lib.mjml.mj_attributes", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.mj_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_attributes.html#emailer_lib.mjml.mj_attributes", "dispname": "emailer_lib.mjml.mj_attributes"}, {"name": "emailer_lib.mjml.mj_all", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_all.html#emailer_lib.mjml.mj_all", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.mj_all", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_all.html#emailer_lib.mjml.mj_all", "dispname": "emailer_lib.mjml.mj_all"}, {"name": "emailer_lib.mjml.mj_class", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_class.html#emailer_lib.mjml.mj_class", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.mj_class", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_class.html#emailer_lib.mjml.mj_class", "dispname": "emailer_lib.mjml.mj_class"}, {"name": "emailer_lib.mjml.breakpoint", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.breakpoint.html#emailer_lib.mjml.breakpoint", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.breakpoint", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.breakpoint.html#emailer_lib.mjml.breakpoint", "dispname": "emailer_lib.mjml.breakpoint"}, {"name": "emailer_lib.mjml.font", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.font.html#emailer_lib.mjml.font", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.font", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.font.html#emailer_lib.mjml.font", "dispname": "emailer_lib.mjml.font"}, {"name": "emailer_lib.mjml.html_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attributes.html#emailer_lib.mjml.html_attributes", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.html_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attributes.html#emailer_lib.mjml.html_attributes", "dispname": "emailer_lib.mjml.html_attributes"}, {"name": "emailer_lib.mjml.html_attribute", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attribute.html#emailer_lib.mjml.html_attribute", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.html_attribute", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attribute.html#emailer_lib.mjml.html_attribute", "dispname": "emailer_lib.mjml.html_attribute"}, {"name": "emailer_lib.mjml.preview", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.preview.html#emailer_lib.mjml.preview", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.preview", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.preview.html#emailer_lib.mjml.preview", "dispname": "emailer_lib.mjml.preview"}, {"name": "emailer_lib.mjml.style", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.style.html#emailer_lib.mjml.style", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.style", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.style.html#emailer_lib.mjml.style", "dispname": "emailer_lib.mjml.style"}, {"name": "emailer_lib.mjml.title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.title.html#emailer_lib.mjml.title", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.title.html#emailer_lib.mjml.title", "dispname": "emailer_lib.mjml.title"}, {"name": "emailer_lib.mjml.accordion", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion.html#emailer_lib.mjml.accordion", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.accordion", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion.html#emailer_lib.mjml.accordion", "dispname": "emailer_lib.mjml.accordion"}, {"name": "emailer_lib.mjml.accordion_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_element.html#emailer_lib.mjml.accordion_element", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.accordion_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_element.html#emailer_lib.mjml.accordion_element", "dispname": "emailer_lib.mjml.accordion_element"}, {"name": "emailer_lib.mjml.accordion_text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_text.html#emailer_lib.mjml.accordion_text", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.accordion_text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_text.html#emailer_lib.mjml.accordion_text", "dispname": "emailer_lib.mjml.accordion_text"}, {"name": "emailer_lib.mjml.accordion_title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_title.html#emailer_lib.mjml.accordion_title", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.accordion_title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_title.html#emailer_lib.mjml.accordion_title", "dispname": "emailer_lib.mjml.accordion_title"}, {"name": "emailer_lib.mjml.button", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.button.html#emailer_lib.mjml.button", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.button", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.button.html#emailer_lib.mjml.button", "dispname": "emailer_lib.mjml.button"}, {"name": "emailer_lib.mjml.carousel", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel.html#emailer_lib.mjml.carousel", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.carousel", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel.html#emailer_lib.mjml.carousel", "dispname": "emailer_lib.mjml.carousel"}, {"name": "emailer_lib.mjml.carousel_image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel_image.html#emailer_lib.mjml.carousel_image", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.carousel_image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel_image.html#emailer_lib.mjml.carousel_image", "dispname": "emailer_lib.mjml.carousel_image"}, {"name": "emailer_lib.mjml.column", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.column.html#emailer_lib.mjml.column", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.column", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.column.html#emailer_lib.mjml.column", "dispname": "emailer_lib.mjml.column"}, {"name": "emailer_lib.mjml.divider", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.divider.html#emailer_lib.mjml.divider", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.divider", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.divider.html#emailer_lib.mjml.divider", "dispname": "emailer_lib.mjml.divider"}, {"name": "emailer_lib.mjml.group", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.group.html#emailer_lib.mjml.group", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.group", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.group.html#emailer_lib.mjml.group", "dispname": "emailer_lib.mjml.group"}, {"name": "emailer_lib.mjml.hero", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.hero.html#emailer_lib.mjml.hero", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.hero", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.hero.html#emailer_lib.mjml.hero", "dispname": "emailer_lib.mjml.hero"}, {"name": "emailer_lib.mjml.image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.image.html#emailer_lib.mjml.image", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.image.html#emailer_lib.mjml.image", "dispname": "emailer_lib.mjml.image"}, {"name": "emailer_lib.mjml.navbar", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar.html#emailer_lib.mjml.navbar", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.navbar", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar.html#emailer_lib.mjml.navbar", "dispname": "emailer_lib.mjml.navbar"}, {"name": "emailer_lib.mjml.navbar_link", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar_link.html#emailer_lib.mjml.navbar_link", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.navbar_link", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar_link.html#emailer_lib.mjml.navbar_link", "dispname": "emailer_lib.mjml.navbar_link"}, {"name": "emailer_lib.mjml.raw", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.raw.html#emailer_lib.mjml.raw", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.raw", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.raw.html#emailer_lib.mjml.raw", "dispname": "emailer_lib.mjml.raw"}, {"name": "emailer_lib.mjml.section", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.section.html#emailer_lib.mjml.section", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.section", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.section.html#emailer_lib.mjml.section", "dispname": "emailer_lib.mjml.section"}, {"name": "emailer_lib.mjml.social", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social.html#emailer_lib.mjml.social", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.social", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social.html#emailer_lib.mjml.social", "dispname": "emailer_lib.mjml.social"}, {"name": "emailer_lib.mjml.social_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social_element.html#emailer_lib.mjml.social_element", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.social_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social_element.html#emailer_lib.mjml.social_element", "dispname": "emailer_lib.mjml.social_element"}, {"name": "emailer_lib.mjml.spacer", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.spacer.html#emailer_lib.mjml.spacer", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.spacer", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.spacer.html#emailer_lib.mjml.spacer", "dispname": "emailer_lib.mjml.spacer"}, {"name": "emailer_lib.mjml.table", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.table.html#emailer_lib.mjml.table", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.table", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.table.html#emailer_lib.mjml.table", "dispname": "emailer_lib.mjml.table"}, {"name": "emailer_lib.mjml.text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.text.html#emailer_lib.mjml.text", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.text.html#emailer_lib.mjml.text", "dispname": "emailer_lib.mjml.text"}, {"name": "emailer_lib.mjml.wrapper", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.wrapper.html#emailer_lib.mjml.wrapper", "dispname": "-"}, {"name": "emailer_lib.mjml.tags.wrapper", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.wrapper.html#emailer_lib.mjml.wrapper", "dispname": "emailer_lib.mjml.wrapper"}]} \ No newline at end of file +{"project": "nbmail", "version": "0.0.9999", "count": 106, "items": [{"name": "nbmail.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.preview_send_email.html#nbmail.IntermediateEmail.preview_send_email", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.preview_send_email.html#nbmail.IntermediateEmail.preview_send_email", "dispname": "nbmail.IntermediateEmail.preview_send_email"}, {"name": "nbmail.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.write_email_message.html#nbmail.IntermediateEmail.write_email_message", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.write_email_message.html#nbmail.IntermediateEmail.write_email_message", "dispname": "nbmail.IntermediateEmail.write_email_message"}, {"name": "nbmail.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.write_preview_email.html#nbmail.IntermediateEmail.write_preview_email", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.write_preview_email.html#nbmail.IntermediateEmail.write_preview_email", "dispname": "nbmail.IntermediateEmail.write_preview_email"}, {"name": "nbmail.IntermediateEmail", "domain": "py", "role": "class", "priority": "1", "uri": "reference/IntermediateEmail.html#nbmail.IntermediateEmail", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail", "domain": "py", "role": "class", "priority": "1", "uri": "reference/IntermediateEmail.html#nbmail.IntermediateEmail", "dispname": "nbmail.IntermediateEmail"}, {"name": "nbmail.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_preview_email.html#nbmail.IntermediateEmail.write_preview_email", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_preview_email.html#nbmail.IntermediateEmail.write_preview_email", "dispname": "nbmail.IntermediateEmail.write_preview_email"}, {"name": "nbmail.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_email_message.html#nbmail.IntermediateEmail.write_email_message", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_email_message.html#nbmail.IntermediateEmail.write_email_message", "dispname": "nbmail.IntermediateEmail.write_email_message"}, {"name": "nbmail.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.preview_send_email.html#nbmail.IntermediateEmail.preview_send_email", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.preview_send_email.html#nbmail.IntermediateEmail.preview_send_email", "dispname": "nbmail.IntermediateEmail.preview_send_email"}, {"name": "nbmail.quarto_json_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/quarto_json_to_intermediate_email.html#nbmail.quarto_json_to_intermediate_email", "dispname": "-"}, {"name": "nbmail.ingress.quarto_json_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/quarto_json_to_intermediate_email.html#nbmail.quarto_json_to_intermediate_email", "dispname": "nbmail.quarto_json_to_intermediate_email"}, {"name": "nbmail.mjml_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml_to_intermediate_email.html#nbmail.mjml_to_intermediate_email", "dispname": "-"}, {"name": "nbmail.ingress.mjml_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml_to_intermediate_email.html#nbmail.mjml_to_intermediate_email", "dispname": "nbmail.mjml_to_intermediate_email"}, {"name": "nbmail.redmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/redmail_to_intermediate_email.html#nbmail.redmail_to_intermediate_email", "dispname": "-"}, {"name": "nbmail.ingress.redmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/redmail_to_intermediate_email.html#nbmail.redmail_to_intermediate_email", "dispname": "nbmail.redmail_to_intermediate_email"}, {"name": "nbmail.yagmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/yagmail_to_intermediate_email.html#nbmail.yagmail_to_intermediate_email", "dispname": "-"}, {"name": "nbmail.ingress.yagmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/yagmail_to_intermediate_email.html#nbmail.yagmail_to_intermediate_email", "dispname": "nbmail.yagmail_to_intermediate_email"}, {"name": "nbmail.send_intermediate_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_gmail.html#nbmail.send_intermediate_email_with_gmail", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_gmail.html#nbmail.send_intermediate_email_with_gmail", "dispname": "nbmail.send_intermediate_email_with_gmail"}, {"name": "nbmail.send_intermediate_email_with_smtp", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_smtp.html#nbmail.send_intermediate_email_with_smtp", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_smtp", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_smtp.html#nbmail.send_intermediate_email_with_smtp", "dispname": "nbmail.send_intermediate_email_with_smtp"}, {"name": "nbmail.send_intermediate_email_with_redmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_redmail.html#nbmail.send_intermediate_email_with_redmail", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_redmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_redmail.html#nbmail.send_intermediate_email_with_redmail", "dispname": "nbmail.send_intermediate_email_with_redmail"}, {"name": "nbmail.send_intermediate_email_with_yagmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_yagmail.html#nbmail.send_intermediate_email_with_yagmail", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_yagmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_yagmail.html#nbmail.send_intermediate_email_with_yagmail", "dispname": "nbmail.send_intermediate_email_with_yagmail"}, {"name": "nbmail.send_intermediate_email_with_mailgun", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_mailgun.html#nbmail.send_intermediate_email_with_mailgun", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_mailgun", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_mailgun.html#nbmail.send_intermediate_email_with_mailgun", "dispname": "nbmail.send_intermediate_email_with_mailgun"}, {"name": "nbmail.send_quarto_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_quarto_email_with_gmail.html#nbmail.send_quarto_email_with_gmail", "dispname": "-"}, {"name": "nbmail.egress.send_quarto_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_quarto_email_with_gmail.html#nbmail.send_quarto_email_with_gmail", "dispname": "nbmail.send_quarto_email_with_gmail"}, {"name": "nbmail.write_email_message_to_file", "domain": "py", "role": "function", "priority": "1", "uri": "reference/write_email_message_to_file.html#nbmail.write_email_message_to_file", "dispname": "-"}, {"name": "nbmail.utils.write_email_message_to_file", "domain": "py", "role": "function", "priority": "1", "uri": "reference/write_email_message_to_file.html#nbmail.write_email_message_to_file", "dispname": "nbmail.write_email_message_to_file"}, {"name": "nbmail.mjml.mjml", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mjml.html#nbmail.mjml.mjml", "dispname": "-"}, {"name": "nbmail.mjml.tags.mjml", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mjml.html#nbmail.mjml.mjml", "dispname": "nbmail.mjml.mjml"}, {"name": "nbmail.mjml.head", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.head.html#nbmail.mjml.head", "dispname": "-"}, {"name": "nbmail.mjml.tags.head", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.head.html#nbmail.mjml.head", "dispname": "nbmail.mjml.head"}, {"name": "nbmail.mjml.body", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.body.html#nbmail.mjml.body", "dispname": "-"}, {"name": "nbmail.mjml.tags.body", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.body.html#nbmail.mjml.body", "dispname": "nbmail.mjml.body"}, {"name": "nbmail.mjml.mj_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_attributes.html#nbmail.mjml.mj_attributes", "dispname": "-"}, {"name": "nbmail.mjml.tags.mj_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_attributes.html#nbmail.mjml.mj_attributes", "dispname": "nbmail.mjml.mj_attributes"}, {"name": "nbmail.mjml.mj_all", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_all.html#nbmail.mjml.mj_all", "dispname": "-"}, {"name": "nbmail.mjml.tags.mj_all", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_all.html#nbmail.mjml.mj_all", "dispname": "nbmail.mjml.mj_all"}, {"name": "nbmail.mjml.mj_class", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_class.html#nbmail.mjml.mj_class", "dispname": "-"}, {"name": "nbmail.mjml.tags.mj_class", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_class.html#nbmail.mjml.mj_class", "dispname": "nbmail.mjml.mj_class"}, {"name": "nbmail.mjml.breakpoint", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.breakpoint.html#nbmail.mjml.breakpoint", "dispname": "-"}, {"name": "nbmail.mjml.tags.breakpoint", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.breakpoint.html#nbmail.mjml.breakpoint", "dispname": "nbmail.mjml.breakpoint"}, {"name": "nbmail.mjml.font", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.font.html#nbmail.mjml.font", "dispname": "-"}, {"name": "nbmail.mjml.tags.font", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.font.html#nbmail.mjml.font", "dispname": "nbmail.mjml.font"}, {"name": "nbmail.mjml.html_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attributes.html#nbmail.mjml.html_attributes", "dispname": "-"}, {"name": "nbmail.mjml.tags.html_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attributes.html#nbmail.mjml.html_attributes", "dispname": "nbmail.mjml.html_attributes"}, {"name": "nbmail.mjml.html_attribute", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attribute.html#nbmail.mjml.html_attribute", "dispname": "-"}, {"name": "nbmail.mjml.tags.html_attribute", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attribute.html#nbmail.mjml.html_attribute", "dispname": "nbmail.mjml.html_attribute"}, {"name": "nbmail.mjml.preview", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.preview.html#nbmail.mjml.preview", "dispname": "-"}, {"name": "nbmail.mjml.tags.preview", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.preview.html#nbmail.mjml.preview", "dispname": "nbmail.mjml.preview"}, {"name": "nbmail.mjml.style", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.style.html#nbmail.mjml.style", "dispname": "-"}, {"name": "nbmail.mjml.tags.style", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.style.html#nbmail.mjml.style", "dispname": "nbmail.mjml.style"}, {"name": "nbmail.mjml.title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.title.html#nbmail.mjml.title", "dispname": "-"}, {"name": "nbmail.mjml.tags.title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.title.html#nbmail.mjml.title", "dispname": "nbmail.mjml.title"}, {"name": "nbmail.mjml.accordion", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion.html#nbmail.mjml.accordion", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion.html#nbmail.mjml.accordion", "dispname": "nbmail.mjml.accordion"}, {"name": "nbmail.mjml.accordion_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_element.html#nbmail.mjml.accordion_element", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_element.html#nbmail.mjml.accordion_element", "dispname": "nbmail.mjml.accordion_element"}, {"name": "nbmail.mjml.accordion_text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_text.html#nbmail.mjml.accordion_text", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion_text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_text.html#nbmail.mjml.accordion_text", "dispname": "nbmail.mjml.accordion_text"}, {"name": "nbmail.mjml.accordion_title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_title.html#nbmail.mjml.accordion_title", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion_title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_title.html#nbmail.mjml.accordion_title", "dispname": "nbmail.mjml.accordion_title"}, {"name": "nbmail.mjml.button", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.button.html#nbmail.mjml.button", "dispname": "-"}, {"name": "nbmail.mjml.tags.button", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.button.html#nbmail.mjml.button", "dispname": "nbmail.mjml.button"}, {"name": "nbmail.mjml.carousel", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel.html#nbmail.mjml.carousel", "dispname": "-"}, {"name": "nbmail.mjml.tags.carousel", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel.html#nbmail.mjml.carousel", "dispname": "nbmail.mjml.carousel"}, {"name": "nbmail.mjml.carousel_image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel_image.html#nbmail.mjml.carousel_image", "dispname": "-"}, {"name": "nbmail.mjml.tags.carousel_image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel_image.html#nbmail.mjml.carousel_image", "dispname": "nbmail.mjml.carousel_image"}, {"name": "nbmail.mjml.column", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.column.html#nbmail.mjml.column", "dispname": "-"}, {"name": "nbmail.mjml.tags.column", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.column.html#nbmail.mjml.column", "dispname": "nbmail.mjml.column"}, {"name": "nbmail.mjml.divider", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.divider.html#nbmail.mjml.divider", "dispname": "-"}, {"name": "nbmail.mjml.tags.divider", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.divider.html#nbmail.mjml.divider", "dispname": "nbmail.mjml.divider"}, {"name": "nbmail.mjml.group", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.group.html#nbmail.mjml.group", "dispname": "-"}, {"name": "nbmail.mjml.tags.group", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.group.html#nbmail.mjml.group", "dispname": "nbmail.mjml.group"}, {"name": "nbmail.mjml.hero", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.hero.html#nbmail.mjml.hero", "dispname": "-"}, {"name": "nbmail.mjml.tags.hero", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.hero.html#nbmail.mjml.hero", "dispname": "nbmail.mjml.hero"}, {"name": "nbmail.mjml.image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.image.html#nbmail.mjml.image", "dispname": "-"}, {"name": "nbmail.mjml.tags.image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.image.html#nbmail.mjml.image", "dispname": "nbmail.mjml.image"}, {"name": "nbmail.mjml.navbar", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar.html#nbmail.mjml.navbar", "dispname": "-"}, {"name": "nbmail.mjml.tags.navbar", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar.html#nbmail.mjml.navbar", "dispname": "nbmail.mjml.navbar"}, {"name": "nbmail.mjml.navbar_link", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar_link.html#nbmail.mjml.navbar_link", "dispname": "-"}, {"name": "nbmail.mjml.tags.navbar_link", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar_link.html#nbmail.mjml.navbar_link", "dispname": "nbmail.mjml.navbar_link"}, {"name": "nbmail.mjml.raw", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.raw.html#nbmail.mjml.raw", "dispname": "-"}, {"name": "nbmail.mjml.tags.raw", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.raw.html#nbmail.mjml.raw", "dispname": "nbmail.mjml.raw"}, {"name": "nbmail.mjml.section", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.section.html#nbmail.mjml.section", "dispname": "-"}, {"name": "nbmail.mjml.tags.section", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.section.html#nbmail.mjml.section", "dispname": "nbmail.mjml.section"}, {"name": "nbmail.mjml.social", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social.html#nbmail.mjml.social", "dispname": "-"}, {"name": "nbmail.mjml.tags.social", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social.html#nbmail.mjml.social", "dispname": "nbmail.mjml.social"}, {"name": "nbmail.mjml.social_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social_element.html#nbmail.mjml.social_element", "dispname": "-"}, {"name": "nbmail.mjml.tags.social_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social_element.html#nbmail.mjml.social_element", "dispname": "nbmail.mjml.social_element"}, {"name": "nbmail.mjml.spacer", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.spacer.html#nbmail.mjml.spacer", "dispname": "-"}, {"name": "nbmail.mjml.tags.spacer", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.spacer.html#nbmail.mjml.spacer", "dispname": "nbmail.mjml.spacer"}, {"name": "nbmail.mjml.table", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.table.html#nbmail.mjml.table", "dispname": "-"}, {"name": "nbmail.mjml.tags.table", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.table.html#nbmail.mjml.table", "dispname": "nbmail.mjml.table"}, {"name": "nbmail.mjml.text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.text.html#nbmail.mjml.text", "dispname": "-"}, {"name": "nbmail.mjml.tags.text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.text.html#nbmail.mjml.text", "dispname": "nbmail.mjml.text"}, {"name": "nbmail.mjml.wrapper", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.wrapper.html#nbmail.mjml.wrapper", "dispname": "-"}, {"name": "nbmail.mjml.tags.wrapper", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.wrapper.html#nbmail.mjml.wrapper", "dispname": "nbmail.mjml.wrapper"}]} diff --git a/docs/summary.quarto_ipynb b/docs/summary.quarto_ipynb new file mode 100644 index 0000000..31b113c --- /dev/null +++ b/docs/summary.quarto_ipynb @@ -0,0 +1,251 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The whole game\n", + "\n", + "\n", + "\n", + "Emailing reports is a critical but challenging task for data science.\n", + "Mainly because you have to figure out generating the email content, configuring pieces like attachments, and orchestrating it (e.g. testing, or sending on a schedule). Moreover, content can range from simple layouts to more complex ones.\n", + "\n", + "In this tutorial, we'll walk through the whole game of sending email. We'll start with this simple example:\n" + ], + "id": "14101fd1" + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# | code-fold: true\n", + "# | eval: false\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from data_polars import sp500\n", + "import redmail\n", + "\n", + "load_dotenv()\n", + "gmail_address = os.environ[\"GMAIL_ADDRESS\"]\n", + "gmail_app_password = os.environ[\"GMAIL_APP_PASSWORD\"]\n", + "\n", + "\n", + "email_subject = \"Report on Cars\"\n", + "email_body = sp500.head(10).style.as_raw_html(inline_css=True)\n", + "\n", + "# This is here to emphasize the sender does not have to be the same as the receiver\n", + "email_receiver = gmail_address\n", + "\n", + "redmail.gmail.username = gmail_address\n", + "redmail.gmail.password = gmail_app_password\n", + "\n", + "redmail.gmail.send(\n", + " subject=email_subject,\n", + " receivers=[email_receiver],\n", + " html=email_body,\n", + ")" + ], + "id": "3e29c5ba", + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![](./assets/whole-game-email-annotated.png){width=50% fig-align=\"center\"}\n", + "\n", + "* **Content**: writing the text of the email, including plots and tables.\n", + "* **Composing**: setting up the subject, sender, and receivers.\n", + "* **Orchestrating**: previewing, testing, and scheduling the email.\n", + "\n", + "We'll also quickly review writing more advanced content layouts, and authoring email reports that involve running code with Quarto.\n", + "\n", + "## A simple email\n", + "\n", + "![](./assets/whole-game-email.png){width=50% fig-align=\"center\"}\n", + "\n", + "* Generate and preview\n", + "* Authenticate (may need to refer to its own authentication page in guide)\n", + "* Send\n" + ], + "id": "31ca0b47" + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# | code-fold: true\n", + "# | eval: false\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from data_polars import sp500\n", + "import redmail\n", + "\n", + "load_dotenv()\n", + "gmail_address = os.environ[\"GMAIL_ADDRESS\"]\n", + "gmail_app_password = os.environ[\"GMAIL_APP_PASSWORD\"]\n", + "\n", + "\n", + "email_subject = \"Report on Cars\"\n", + "email_body = sp500.head(10).style.as_raw_html(inline_css=True)\n", + "\n", + "# This is here to emphasize the sender does not have to be the same as the receiver\n", + "email_receiver = gmail_address\n", + "\n", + "redmail.gmail.username = gmail_address\n", + "redmail.gmail.password = gmail_app_password\n", + "\n", + "redmail.gmail.send(\n", + " subject=email_subject,\n", + " receivers=[email_receiver],\n", + " html=email_body,\n", + ")" + ], + "id": "ecc38edf", + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Configure: subject, recipients, attachments\n", + "\n", + "* you could attach the data as a CSV attachment\n", + "\n", + "\n", + "## Orchestrate: save and preview\n", + "\n", + "* previewing email\n", + "* intermediate json, easy for sending email later\n", + "* embedding images makes previewing hard\n", + "* can always email to yourself (or use a test service like Litmus)\n", + "\n", + "## Content: Quarto authoring\n", + "\n", + "Here's our same simple email generated using quarto.\n", + "\n", + "\n", + "\n", + "![](./assets/whole-game-quarto.png){width=50% fig-align=\"center\"}\n", + "\n", + "* Focused on basic configuring, and content\n", + "* Sending happens via our tool\n", + "* Generate using quarto render\n", + "* Can preview email\n", + "\n", + "## Content: advanced layouts\n", + "\n", + "We'll highlight the key pieces (discussed later in this guide) to go from that simple email, to a more advanced on like below:\n", + "\n", + "![](./assets/whole-game-fancy.png){width=50% fig-align=\"center\"}\n", + "\n", + "\n", + "## Fridge\n", + "\n", + "In this tutorial, we are going to send an email from a Gmail account. To do so, you will need to [create an App Password](https://support.google.com/accounts/answer/185833). Note this is only possible if you've [enabled 2-step verification](https://support.google.com/accounts/answer/185839).\n", + "\n", + "\n", + "\n", + "::: {.callout-tip}\n", + "This is just one of many options: it is also possible to send emails in Python from other email providers (Outlook, ProtonMail, etc.), or even from a custom domain. To skip ahead to a discussion of alternative sending methods, see [Authentication](orchestrating-auth.qmd)\n", + ":::\n", + "\n", + "Once you've created your App Password, that is used as your Gmail password for sending with Python. \n", + "\n", + "There are many ways to store the password seperate from your email-sending code, so as to not expose any sensitive information. One such approach uses a `.env` file, and the ``dotenv` and `os` packages.\n", + "\n", + "```{.sh filename=\".env\"}\n", + "GMAIL_APP_PASSWORD=abcd abcd abcd abcd\n", + "```\n", + "\n", + "```{.python filename=\"main.py\"}\n", + "import os\n", + "from dotenv import load_dotenv\n", + "\n", + "load_dotenv()\n", + "\n", + "your_gmail_address = \"YourGmail@gmail.com\"\n", + "gmail_app_password = os.environ[\"GMAIL_APP_PASSWORD\"]\n", + "```\n", + "\n", + "Check out the email content we will send.\n" + ], + "id": "840912f2" + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "from data_polars import sp500\n", + "\n", + "sp500.head(10).style" + ], + "id": "0cda1fb2", + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And now we send the email!\n" + ], + "id": "f44aff8c" + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# | eval: false\n", + "import redmail\n", + "\n", + "redmail.gmail.username = your_gmail_address\n", + "redmail.gmail.password = gmail_app_password\n", + "\n", + "redmail.gmail.send(\n", + " subject=\"An Example Email\",\n", + " receivers=[username],\n", + " html=email_html,\n", + " text=email_plaintext,\n", + ")" + ], + "id": "4ad22022", + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ], + "id": "15ee0056" + } + ], + "metadata": { + "kernelspec": { + "name": "python3", + "language": "python", + "display_name": "Python 3 (ipykernel)", + "path": "/Users/jules-wg/Library/Python/3.9/share/jupyter/kernels/python3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/examples/.gitignore b/examples/.gitignore index bd2bfd4..a131850 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,2 +1,2 @@ playground.qmd -emailer_lib.qmd \ No newline at end of file +nbmail.qmd diff --git a/examples/emailer_lib.qmd b/examples/emailer_lib.qmd new file mode 100644 index 0000000..e69de29 diff --git a/emailer_lib/__init__.py b/nbmail/__init__.py similarity index 100% rename from emailer_lib/__init__.py rename to nbmail/__init__.py diff --git a/emailer_lib/egress.py b/nbmail/egress.py similarity index 100% rename from emailer_lib/egress.py rename to nbmail/egress.py diff --git a/emailer_lib/ingress.py b/nbmail/ingress.py similarity index 100% rename from emailer_lib/ingress.py rename to nbmail/ingress.py diff --git a/emailer_lib/mjml/.gitignore b/nbmail/mjml/.gitignore similarity index 100% rename from emailer_lib/mjml/.gitignore rename to nbmail/mjml/.gitignore diff --git a/emailer_lib/mjml/README.md b/nbmail/mjml/README.md similarity index 91% rename from emailer_lib/mjml/README.md rename to nbmail/mjml/README.md index 16efad3..2b3c624 100644 --- a/emailer_lib/mjml/README.md +++ b/nbmail/mjml/README.md @@ -14,16 +14,16 @@ This module provides Python functions for creating MJML markup, the responsive e ## Installation -This module is part of the `emailer_lib` package: +This module is part of the `nbmail` package: ```python -from emailer_lib import mjml as mj +from nbmail import mjml as mj ``` ## Quick Start ```python -from emailer_lib.mjml import mjml, body, section, column, text +from nbmail.mjml import mjml, body, section, column, text # Build an MJML email structure email = mjml( @@ -99,7 +99,7 @@ button( The base class for all MJML elements. Can be instantiated directly or via helper functions. ```python -from emailer_lib.mjml import MJMLTag +from nbmail.mjml import MJMLTag tag = MJMLTag( "mj-text", @@ -117,7 +117,7 @@ A dictionary type for tag attributes. ### Simple Email ```python -from emailer_lib.mjml import mjml, head, body, section, column, text, title +from nbmail.mjml import mjml, head, body, section, column, text, title email = mjml( head( @@ -136,7 +136,7 @@ email = mjml( ### Multi-column Layout ```python -from emailer_lib.mjml import body, section, column, text, image +from nbmail.mjml import body, section, column, text, image layout = body( section( @@ -157,7 +157,7 @@ layout = body( ### Using Attributes ```python -from emailer_lib.mjml import section, column, text +from nbmail.mjml import section, column, text # Attributes as kwargs section( diff --git a/emailer_lib/mjml/__init__.py b/nbmail/mjml/__init__.py similarity index 100% rename from emailer_lib/mjml/__init__.py rename to nbmail/mjml/__init__.py diff --git a/emailer_lib/mjml/_core.py b/nbmail/mjml/_core.py similarity index 100% rename from emailer_lib/mjml/_core.py rename to nbmail/mjml/_core.py diff --git a/emailer_lib/mjml/image_processor.py b/nbmail/mjml/image_processor.py similarity index 97% rename from emailer_lib/mjml/image_processor.py rename to nbmail/mjml/image_processor.py index 02c61ed..4395686 100644 --- a/emailer_lib/mjml/image_processor.py +++ b/nbmail/mjml/image_processor.py @@ -73,8 +73,8 @@ def _process_mjml_images(mjml_tag: MJMLTag) -> Tuple[MJMLTag, Dict[str, str]]: Examples -------- ```python - from emailer_lib.mjml import mjml, body, section, column, image - from emailer_lib import mjml_to_intermediate_email + from nbmail.mjml import mjml, body, section, column, image + from nbmail import mjml_to_intermediate_email from io import BytesIO # Create BytesIO with image data diff --git a/emailer_lib/mjml/scripts/generate_tags.py b/nbmail/mjml/scripts/generate_tags.py similarity index 96% rename from emailer_lib/mjml/scripts/generate_tags.py rename to nbmail/mjml/scripts/generate_tags.py index d84b7f0..86fae9a 100644 --- a/emailer_lib/mjml/scripts/generate_tags.py +++ b/nbmail/mjml/scripts/generate_tags.py @@ -115,7 +115,7 @@ def {py_name}( -------- With children: ```{{python}} - from emailer_lib.mjml import {py_name}, text + from nbmail.mjml import {py_name}, text child = text("Hello World") result = {py_name}(child) @@ -165,7 +165,7 @@ def {py_name}( -------- With content: ```{{python}} - from emailer_lib.mjml import {py_name} + from nbmail.mjml import {py_name} result = {py_name}("Hello") ``` @@ -182,7 +182,7 @@ def {py_name}( # Combine all parts output = header + "\n".join(functions) - # Write to file - navigate from scripts/ to emailer_lib/mjml/tags.py + # Write to file - navigate from scripts/ to nbmail/mjml/tags.py script_dir = Path(__file__).parent tags_file = script_dir.parent / "tags.py" diff --git a/emailer_lib/mjml/tags.py b/nbmail/mjml/tags.py similarity index 94% rename from emailer_lib/mjml/tags.py rename to nbmail/mjml/tags.py index 1cdbf1c..3589fc7 100644 --- a/emailer_lib/mjml/tags.py +++ b/nbmail/mjml/tags.py @@ -35,7 +35,7 @@ def mjml( -------- With children: ```{python} - from emailer_lib.mjml import mjml, text + from nbmail.mjml import mjml, text child = text("Hello World") result = mjml(child) @@ -80,7 +80,7 @@ def head( -------- With children: ```{python} - from emailer_lib.mjml import head, text + from nbmail.mjml import head, text child = text("Hello World") result = head(child) @@ -125,7 +125,7 @@ def body( -------- With children: ```{python} - from emailer_lib.mjml import body, text + from nbmail.mjml import body, text child = text("Hello World") result = body(child) @@ -170,7 +170,7 @@ def mj_attributes( -------- With children: ```{python} - from emailer_lib.mjml import mj_attributes, text + from nbmail.mjml import mj_attributes, text child = text("Hello World") result = mj_attributes(child) @@ -215,7 +215,7 @@ def mj_all( -------- With children: ```{python} - from emailer_lib.mjml import mj_all, text + from nbmail.mjml import mj_all, text child = text("Hello World") result = mj_all(child) @@ -260,7 +260,7 @@ def mj_class( -------- With children: ```{python} - from emailer_lib.mjml import mj_class, text + from nbmail.mjml import mj_class, text child = text("Hello World") result = mj_class(child) @@ -305,7 +305,7 @@ def breakpoint( -------- With children: ```{python} - from emailer_lib.mjml import breakpoint, text + from nbmail.mjml import breakpoint, text child = text("Hello World") result = breakpoint(child) @@ -350,7 +350,7 @@ def font( -------- With children: ```{python} - from emailer_lib.mjml import font, text + from nbmail.mjml import font, text child = text("Hello World") result = font(child) @@ -395,7 +395,7 @@ def html_attributes( -------- With children: ```{python} - from emailer_lib.mjml import html_attributes, text + from nbmail.mjml import html_attributes, text child = text("Hello World") result = html_attributes(child) @@ -440,7 +440,7 @@ def html_attribute( -------- With children: ```{python} - from emailer_lib.mjml import html_attribute, text + from nbmail.mjml import html_attribute, text child = text("Hello World") result = html_attribute(child) @@ -485,7 +485,7 @@ def preview( -------- With children: ```{python} - from emailer_lib.mjml import preview, text + from nbmail.mjml import preview, text child = text("Hello World") result = preview(child) @@ -530,7 +530,7 @@ def style( -------- With children: ```{python} - from emailer_lib.mjml import style, text + from nbmail.mjml import style, text child = text("Hello World") result = style(child) @@ -575,7 +575,7 @@ def accordion( -------- With children: ```{python} - from emailer_lib.mjml import accordion, text + from nbmail.mjml import accordion, text child = text("Hello World") result = accordion(child) @@ -620,7 +620,7 @@ def accordion_element( -------- With children: ```{python} - from emailer_lib.mjml import accordion_element, text + from nbmail.mjml import accordion_element, text child = text("Hello World") result = accordion_element(child) @@ -665,7 +665,7 @@ def carousel( -------- With children: ```{python} - from emailer_lib.mjml import carousel, text + from nbmail.mjml import carousel, text child = text("Hello World") result = carousel(child) @@ -710,7 +710,7 @@ def column( -------- With children: ```{python} - from emailer_lib.mjml import column, text + from nbmail.mjml import column, text child = text("Hello World") result = column(child) @@ -755,7 +755,7 @@ def divider( -------- With children: ```{python} - from emailer_lib.mjml import divider, text + from nbmail.mjml import divider, text child = text("Hello World") result = divider(child) @@ -800,7 +800,7 @@ def group( -------- With children: ```{python} - from emailer_lib.mjml import group, text + from nbmail.mjml import group, text child = text("Hello World") result = group(child) @@ -845,7 +845,7 @@ def hero( -------- With children: ```{python} - from emailer_lib.mjml import hero, text + from nbmail.mjml import hero, text child = text("Hello World") result = hero(child) @@ -890,7 +890,7 @@ def image( -------- With children: ```{python} - from emailer_lib.mjml import image, text + from nbmail.mjml import image, text child = text("Hello World") result = image(child) @@ -935,7 +935,7 @@ def navbar( -------- With children: ```{python} - from emailer_lib.mjml import navbar, text + from nbmail.mjml import navbar, text child = text("Hello World") result = navbar(child) @@ -980,7 +980,7 @@ def section( -------- With children: ```{python} - from emailer_lib.mjml import section, text + from nbmail.mjml import section, text child = text("Hello World") result = section(child) @@ -1025,7 +1025,7 @@ def social( -------- With children: ```{python} - from emailer_lib.mjml import social, text + from nbmail.mjml import social, text child = text("Hello World") result = social(child) @@ -1070,7 +1070,7 @@ def spacer( -------- With children: ```{python} - from emailer_lib.mjml import spacer, text + from nbmail.mjml import spacer, text child = text("Hello World") result = spacer(child) @@ -1115,7 +1115,7 @@ def wrapper( -------- With children: ```{python} - from emailer_lib.mjml import wrapper, text + from nbmail.mjml import wrapper, text child = text("Hello World") result = wrapper(child) @@ -1159,7 +1159,7 @@ def accordion_text( -------- With content: ```{python} - from emailer_lib.mjml import accordion_text + from nbmail.mjml import accordion_text result = accordion_text("Hello") ``` @@ -1197,7 +1197,7 @@ def accordion_title( -------- With content: ```{python} - from emailer_lib.mjml import accordion_title + from nbmail.mjml import accordion_title result = accordion_title("Hello") ``` @@ -1235,7 +1235,7 @@ def button( -------- With content: ```{python} - from emailer_lib.mjml import button + from nbmail.mjml import button result = button("Hello") ``` @@ -1273,7 +1273,7 @@ def carousel_image( -------- With content: ```{python} - from emailer_lib.mjml import carousel_image + from nbmail.mjml import carousel_image result = carousel_image("Hello") ``` @@ -1311,7 +1311,7 @@ def navbar_link( -------- With content: ```{python} - from emailer_lib.mjml import navbar_link + from nbmail.mjml import navbar_link result = navbar_link("Hello") ``` @@ -1349,7 +1349,7 @@ def raw( -------- With content: ```{python} - from emailer_lib.mjml import raw + from nbmail.mjml import raw result = raw("Hello") ``` @@ -1387,7 +1387,7 @@ def social_element( -------- With content: ```{python} - from emailer_lib.mjml import social_element + from nbmail.mjml import social_element result = social_element("Hello") ``` @@ -1425,7 +1425,7 @@ def table( -------- With content: ```{python} - from emailer_lib.mjml import table + from nbmail.mjml import table result = table("Hello") ``` @@ -1463,7 +1463,7 @@ def text( -------- With content: ```{python} - from emailer_lib.mjml import text + from nbmail.mjml import text result = text("Hello") ``` @@ -1501,7 +1501,7 @@ def title( -------- With content: ```{python} - from emailer_lib.mjml import title + from nbmail.mjml import title result = title("Hello") ``` diff --git a/emailer_lib/mjml/tests/test_core.py b/nbmail/mjml/tests/test_core.py similarity index 98% rename from emailer_lib/mjml/tests/test_core.py rename to nbmail/mjml/tests/test_core.py index 6069c15..05bcffd 100644 --- a/emailer_lib/mjml/tests/test_core.py +++ b/nbmail/mjml/tests/test_core.py @@ -1,7 +1,7 @@ import pytest from io import BytesIO -from emailer_lib.ingress import mjml_to_intermediate_email -from emailer_lib.mjml._core import MJMLTag, TagAttrDict +from nbmail.ingress import mjml_to_intermediate_email +from nbmail.mjml._core import MJMLTag, TagAttrDict def test_accepts_dict_arguments(): diff --git a/emailer_lib/mjml/tests/test_image_processor.py b/nbmail/mjml/tests/test_image_processor.py similarity index 97% rename from emailer_lib/mjml/tests/test_image_processor.py rename to nbmail/mjml/tests/test_image_processor.py index 5fe2f5c..ecd5d97 100644 --- a/emailer_lib/mjml/tests/test_image_processor.py +++ b/nbmail/mjml/tests/test_image_processor.py @@ -1,8 +1,8 @@ import pytest from io import BytesIO -from emailer_lib.mjml.image_processor import _convert_to_bytes, _process_mjml_images -from emailer_lib.mjml._core import MJMLTag +from nbmail.mjml.image_processor import _convert_to_bytes, _process_mjml_images +from nbmail.mjml._core import MJMLTag def test_convert_to_bytes_from_bytesio(): diff --git a/emailer_lib/mjml/tests/test_tags.py b/nbmail/mjml/tests/test_tags.py similarity index 99% rename from emailer_lib/mjml/tests/test_tags.py rename to nbmail/mjml/tests/test_tags.py index 3ea9305..0b4f5d0 100644 --- a/emailer_lib/mjml/tests/test_tags.py +++ b/nbmail/mjml/tests/test_tags.py @@ -1,5 +1,5 @@ import pytest -from emailer_lib.mjml import ( +from nbmail.mjml import ( MJMLTag, mjml, head, diff --git a/emailer_lib/structs.py b/nbmail/structs.py similarity index 100% rename from emailer_lib/structs.py rename to nbmail/structs.py diff --git a/emailer_lib/tests/__snapshots__/test_structs.ambr b/nbmail/tests/__snapshots__/test_structs.ambr similarity index 100% rename from emailer_lib/tests/__snapshots__/test_structs.ambr rename to nbmail/tests/__snapshots__/test_structs.ambr diff --git a/emailer_lib/tests/test_egress.py b/nbmail/tests/test_egress.py similarity index 94% rename from emailer_lib/tests/test_egress.py rename to nbmail/tests/test_egress.py index e8abc65..26200af 100644 --- a/emailer_lib/tests/test_egress.py +++ b/nbmail/tests/test_egress.py @@ -2,7 +2,7 @@ import pytest -from emailer_lib.egress import ( +from nbmail.egress import ( send_intermediate_email_with_redmail, send_intermediate_email_with_yagmail, send_intermediate_email_with_mailgun, @@ -10,7 +10,7 @@ send_intermediate_email_with_gmail, send_quarto_email_with_gmail, ) -from emailer_lib.structs import IntermediateEmail +from nbmail.structs import IntermediateEmail def make_basic_email(): @@ -31,9 +31,9 @@ def setup_smtp_mocks(monkeypatch): context = mock_smtp.return_value.__enter__.return_value - # Patch in the emailer_lib.egress module where they're used - monkeypatch.setattr("emailer_lib.egress.smtplib.SMTP", mock_smtp) - monkeypatch.setattr("emailer_lib.egress.smtplib.SMTP_SSL", mock_smtp_ssl) + # Patch in the nbmail.egress module where they're used + monkeypatch.setattr("nbmail.egress.smtplib.SMTP", mock_smtp) + monkeypatch.setattr("nbmail.egress.smtplib.SMTP_SSL", mock_smtp_ssl) return mock_smtp, mock_smtp_ssl, context @@ -43,7 +43,7 @@ def test_send_intermediate_email_with_gmail_calls_smtp(monkeypatch): mock_smtp_send = MagicMock() monkeypatch.setattr( - "emailer_lib.egress.send_intermediate_email_with_smtp", mock_smtp_send + "nbmail.egress.send_intermediate_email_with_smtp", mock_smtp_send ) send_intermediate_email_with_gmail("user@gmail.com", "pass", email) @@ -178,13 +178,13 @@ def test_send_quarto_email_with_gmail(monkeypatch): # Mock the quarto_json_to_intermediate_email function mock_quarto_to_email = MagicMock(return_value=make_basic_email()) monkeypatch.setattr( - "emailer_lib.egress.quarto_json_to_intermediate_email", mock_quarto_to_email + "nbmail.egress.quarto_json_to_intermediate_email", mock_quarto_to_email ) # Mock the Gmail sending function mock_send_gmail = MagicMock() monkeypatch.setattr( - "emailer_lib.egress.send_intermediate_email_with_gmail", mock_send_gmail + "nbmail.egress.send_intermediate_email_with_gmail", mock_send_gmail ) # Call the function diff --git a/emailer_lib/tests/test_end_to_end.py b/nbmail/tests/test_end_to_end.py similarity index 93% rename from emailer_lib/tests/test_end_to_end.py rename to nbmail/tests/test_end_to_end.py index 7c01906..42f62fc 100644 --- a/emailer_lib/tests/test_end_to_end.py +++ b/nbmail/tests/test_end_to_end.py @@ -2,8 +2,8 @@ import time from aiosmtpd.controller import Controller from email import message_from_bytes -from emailer_lib.egress import send_intermediate_email_with_smtp -from emailer_lib.structs import IntermediateEmail +from nbmail.egress import send_intermediate_email_with_smtp +from nbmail.structs import IntermediateEmail class EmailHandler: @@ -87,4 +87,4 @@ def test_send_email_integration(smtp_server): inline_images = [p for p in msg.walk() if p.get('Content-ID')] assert len(inline_images) == 1 - assert '' in inline_images[0].get('Content-ID') \ No newline at end of file + assert '' in inline_images[0].get('Content-ID') diff --git a/emailer_lib/tests/test_ingress.py b/nbmail/tests/test_ingress.py similarity index 97% rename from emailer_lib/tests/test_ingress.py rename to nbmail/tests/test_ingress.py index b66abfd..fea863a 100644 --- a/emailer_lib/tests/test_ingress.py +++ b/nbmail/tests/test_ingress.py @@ -3,14 +3,14 @@ from email.message import EmailMessage from base64 import b64encode -from emailer_lib.ingress import ( +from nbmail.ingress import ( redmail_to_intermediate_email, yagmail_to_intermediate_email, mjml_to_intermediate_email, quarto_json_to_intermediate_email, _email_message_to_intermediate_email, ) -from emailer_lib.structs import IntermediateEmail +from nbmail.structs import IntermediateEmail def test_email_message_to_intermediate_email_simple(): @@ -157,7 +157,7 @@ def test_mjml_to_intermediate_email_with_string_url(): def test_mjml_to_intermediate_email_with_bytesio(): from io import BytesIO - from emailer_lib.mjml import mjml, body, section, column, image + from nbmail.mjml import mjml, body, section, column, image buf = BytesIO(b'\x89PNG\r\n\x1a\n') @@ -188,7 +188,7 @@ def test_mjml_to_intermediate_email_with_bytesio(): def test_mjml_to_mjml_with_bytesio_raises_error(): from io import BytesIO - from emailer_lib.mjml import mjml, body, section, column, image + from nbmail.mjml import mjml, body, section, column, image # Create a simple BytesIO object with fake image data buf = BytesIO(b'\x89PNG\r\n\x1a\n') diff --git a/emailer_lib/tests/test_structs.py b/nbmail/tests/test_structs.py similarity index 99% rename from emailer_lib/tests/test_structs.py rename to nbmail/tests/test_structs.py index a5876f7..b60db3e 100644 --- a/emailer_lib/tests/test_structs.py +++ b/nbmail/tests/test_structs.py @@ -1,7 +1,7 @@ import re import pytest -from emailer_lib.structs import IntermediateEmail +from nbmail.structs import IntermediateEmail def test_creation_with_text_and_attachments(): diff --git a/emailer_lib/tests/test_utils.py b/nbmail/tests/test_utils.py similarity index 99% rename from emailer_lib/tests/test_utils.py rename to nbmail/tests/test_utils.py index bf81779..66edb92 100644 --- a/emailer_lib/tests/test_utils.py +++ b/nbmail/tests/test_utils.py @@ -2,7 +2,7 @@ from email.message import EmailMessage import re -from emailer_lib.utils import ( +from nbmail.utils import ( write_email_message_to_file, _add_base_64_to_inline_attachments, ) diff --git a/emailer_lib/utils.py b/nbmail/utils.py similarity index 100% rename from emailer_lib/utils.py rename to nbmail/utils.py diff --git a/pyproject.toml b/pyproject.toml index 916e82a..096c7c9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,11 +6,11 @@ build-backend = "setuptools.build_meta" [tool.pytest.ini_options] minversion = "6.0" -addopts = "-ra --cov=emailer_lib --cov-report=term-missing" -testpaths = ["emailer_lib/**/tests"] +addopts = "-ra --cov=nbmail --cov-report=term-missing" +testpaths = ["nbmail/**/tests"] [project] -name = "emailer-lib" +name = "nbmail" version = "0.0.1" description = "Email serialization and sending utilities" authors = [{name = "Jules Walzer-Goldfeld"}] @@ -55,7 +55,7 @@ docs = [ exclude_also = [ "if TYPE_CHECKING:" ] -include = ["emailer_lib/*"] +include = ["nbmail/*"] omit = [ - "emailer_lib/tests/*" + "nbmail/tests/*" ] diff --git a/uv.lock b/uv.lock index ea5a350..14764be 100644 --- a/uv.lock +++ b/uv.lock @@ -1042,7 +1042,7 @@ wheels = [ ] [[package]] -name = "emailer-lib" +name = "nbmail" version = "0.0.1" source = { editable = "." } dependencies = [ From 8f9f8e9587c5c0d52fed94cc870cc2b09b4dfd8b Mon Sep 17 00:00:00 2001 From: Jules <54960783+juleswg23@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:05:39 -0500 Subject: [PATCH 2/4] rename intermediate email to email --- README.md | 10 ++-- docs/_quarto.yml | 28 +++++------ docs/objects.json | 2 +- docs/summary.quarto_ipynb | 18 ++++---- nbmail/__init__.py | 40 ++++++++-------- nbmail/egress.py | 72 ++++++++++++++--------------- nbmail/ingress.py | 42 ++++++++--------- nbmail/mjml/__init__.py | 2 +- nbmail/mjml/_core.py | 14 +++--- nbmail/mjml/image_processor.py | 8 ++-- nbmail/mjml/tests/test_core.py | 8 ++-- nbmail/structs.py | 16 +++---- nbmail/tests/test_egress.py | 60 ++++++++++++------------ nbmail/tests/test_end_to_end.py | 8 ++-- nbmail/tests/test_ingress.py | 82 ++++++++++++++++----------------- nbmail/tests/test_structs.py | 20 ++++---- 16 files changed, 215 insertions(+), 215 deletions(-) diff --git a/README.md b/README.md index d4b19dc..2c21d00 100644 --- a/README.md +++ b/README.md @@ -32,19 +32,19 @@ pip install -e ./nbmail ```python from nbmail import ( - quarto_json_to_intermediate_email, - IntermediateEmail, - send_intermediate_email_with_gmail, + quarto_json_to_email, + Email, + send_email_with_gmail, ) # Read a Quarto email JSON file -email_struct = quarto_json_to_intermediate_email("email.json") +email_struct = quarto_json_to_email("email.json") # Preview the email as HTML email_struct.write_preview_email("preview.html") # Send the email via Gmail -send_intermediate_email_with_gmail("your_email@gmail.com", "your_password", email_struct) +send_email_with_gmail("your_email@gmail.com", "your_password", email_struct) ``` ## Features diff --git a/docs/_quarto.yml b/docs/_quarto.yml index 78f67c8..6a56812 100644 --- a/docs/_quarto.yml +++ b/docs/_quarto.yml @@ -43,31 +43,31 @@ quartodoc: An email object that in a serializable, previewable format, optimized for emails with content generated by data scientists. contents: - - name: IntermediateEmail + - name: Email children: separate - - name: IntermediateEmail.write_preview_email - - name: IntermediateEmail.write_email_message - - name: IntermediateEmail.preview_send_email + - name: Email.write_preview_email + - name: Email.write_email_message + - name: Email.preview_send_email - title: Uploading emails desc: > - Converting emails to IntermediateEmails, + Converting emails to Emails, at which point they can be previewed, tested, and sent. contents: - - quarto_json_to_intermediate_email - - mjml_to_intermediate_email - - redmail_to_intermediate_email - - yagmail_to_intermediate_email + - quarto_json_to_email + - mjml_to_email + - redmail_to_email + - yagmail_to_email - title: Sending desc: > Functions to sending emails with different providers. And a special handy one to bypass the intermediate object if you are sending a quarto email. contents: - - send_intermediate_email_with_gmail - - send_intermediate_email_with_smtp - - send_intermediate_email_with_redmail - - send_intermediate_email_with_yagmail - - send_intermediate_email_with_mailgun + - send_email_with_gmail + - send_email_with_smtp + - send_email_with_redmail + - send_email_with_yagmail + - send_email_with_mailgun - send_quarto_email_with_gmail - title: Utilities diff --git a/docs/objects.json b/docs/objects.json index fa4a566..073ffef 100644 --- a/docs/objects.json +++ b/docs/objects.json @@ -1 +1 @@ -{"project": "nbmail", "version": "0.0.9999", "count": 106, "items": [{"name": "nbmail.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.preview_send_email.html#nbmail.IntermediateEmail.preview_send_email", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.preview_send_email.html#nbmail.IntermediateEmail.preview_send_email", "dispname": "nbmail.IntermediateEmail.preview_send_email"}, {"name": "nbmail.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.write_email_message.html#nbmail.IntermediateEmail.write_email_message", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.write_email_message.html#nbmail.IntermediateEmail.write_email_message", "dispname": "nbmail.IntermediateEmail.write_email_message"}, {"name": "nbmail.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.write_preview_email.html#nbmail.IntermediateEmail.write_preview_email", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.IntermediateEmail.write_preview_email.html#nbmail.IntermediateEmail.write_preview_email", "dispname": "nbmail.IntermediateEmail.write_preview_email"}, {"name": "nbmail.IntermediateEmail", "domain": "py", "role": "class", "priority": "1", "uri": "reference/IntermediateEmail.html#nbmail.IntermediateEmail", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail", "domain": "py", "role": "class", "priority": "1", "uri": "reference/IntermediateEmail.html#nbmail.IntermediateEmail", "dispname": "nbmail.IntermediateEmail"}, {"name": "nbmail.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_preview_email.html#nbmail.IntermediateEmail.write_preview_email", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_preview_email.html#nbmail.IntermediateEmail.write_preview_email", "dispname": "nbmail.IntermediateEmail.write_preview_email"}, {"name": "nbmail.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_email_message.html#nbmail.IntermediateEmail.write_email_message", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.write_email_message.html#nbmail.IntermediateEmail.write_email_message", "dispname": "nbmail.IntermediateEmail.write_email_message"}, {"name": "nbmail.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.preview_send_email.html#nbmail.IntermediateEmail.preview_send_email", "dispname": "-"}, {"name": "nbmail.structs.IntermediateEmail.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/IntermediateEmail.preview_send_email.html#nbmail.IntermediateEmail.preview_send_email", "dispname": "nbmail.IntermediateEmail.preview_send_email"}, {"name": "nbmail.quarto_json_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/quarto_json_to_intermediate_email.html#nbmail.quarto_json_to_intermediate_email", "dispname": "-"}, {"name": "nbmail.ingress.quarto_json_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/quarto_json_to_intermediate_email.html#nbmail.quarto_json_to_intermediate_email", "dispname": "nbmail.quarto_json_to_intermediate_email"}, {"name": "nbmail.mjml_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml_to_intermediate_email.html#nbmail.mjml_to_intermediate_email", "dispname": "-"}, {"name": "nbmail.ingress.mjml_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml_to_intermediate_email.html#nbmail.mjml_to_intermediate_email", "dispname": "nbmail.mjml_to_intermediate_email"}, {"name": "nbmail.redmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/redmail_to_intermediate_email.html#nbmail.redmail_to_intermediate_email", "dispname": "-"}, {"name": "nbmail.ingress.redmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/redmail_to_intermediate_email.html#nbmail.redmail_to_intermediate_email", "dispname": "nbmail.redmail_to_intermediate_email"}, {"name": "nbmail.yagmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/yagmail_to_intermediate_email.html#nbmail.yagmail_to_intermediate_email", "dispname": "-"}, {"name": "nbmail.ingress.yagmail_to_intermediate_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/yagmail_to_intermediate_email.html#nbmail.yagmail_to_intermediate_email", "dispname": "nbmail.yagmail_to_intermediate_email"}, {"name": "nbmail.send_intermediate_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_gmail.html#nbmail.send_intermediate_email_with_gmail", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_gmail.html#nbmail.send_intermediate_email_with_gmail", "dispname": "nbmail.send_intermediate_email_with_gmail"}, {"name": "nbmail.send_intermediate_email_with_smtp", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_smtp.html#nbmail.send_intermediate_email_with_smtp", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_smtp", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_smtp.html#nbmail.send_intermediate_email_with_smtp", "dispname": "nbmail.send_intermediate_email_with_smtp"}, {"name": "nbmail.send_intermediate_email_with_redmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_redmail.html#nbmail.send_intermediate_email_with_redmail", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_redmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_redmail.html#nbmail.send_intermediate_email_with_redmail", "dispname": "nbmail.send_intermediate_email_with_redmail"}, {"name": "nbmail.send_intermediate_email_with_yagmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_yagmail.html#nbmail.send_intermediate_email_with_yagmail", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_yagmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_yagmail.html#nbmail.send_intermediate_email_with_yagmail", "dispname": "nbmail.send_intermediate_email_with_yagmail"}, {"name": "nbmail.send_intermediate_email_with_mailgun", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_mailgun.html#nbmail.send_intermediate_email_with_mailgun", "dispname": "-"}, {"name": "nbmail.egress.send_intermediate_email_with_mailgun", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_intermediate_email_with_mailgun.html#nbmail.send_intermediate_email_with_mailgun", "dispname": "nbmail.send_intermediate_email_with_mailgun"}, {"name": "nbmail.send_quarto_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_quarto_email_with_gmail.html#nbmail.send_quarto_email_with_gmail", "dispname": "-"}, {"name": "nbmail.egress.send_quarto_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_quarto_email_with_gmail.html#nbmail.send_quarto_email_with_gmail", "dispname": "nbmail.send_quarto_email_with_gmail"}, {"name": "nbmail.write_email_message_to_file", "domain": "py", "role": "function", "priority": "1", "uri": "reference/write_email_message_to_file.html#nbmail.write_email_message_to_file", "dispname": "-"}, {"name": "nbmail.utils.write_email_message_to_file", "domain": "py", "role": "function", "priority": "1", "uri": "reference/write_email_message_to_file.html#nbmail.write_email_message_to_file", "dispname": "nbmail.write_email_message_to_file"}, {"name": "nbmail.mjml.mjml", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mjml.html#nbmail.mjml.mjml", "dispname": "-"}, {"name": "nbmail.mjml.tags.mjml", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mjml.html#nbmail.mjml.mjml", "dispname": "nbmail.mjml.mjml"}, {"name": "nbmail.mjml.head", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.head.html#nbmail.mjml.head", "dispname": "-"}, {"name": "nbmail.mjml.tags.head", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.head.html#nbmail.mjml.head", "dispname": "nbmail.mjml.head"}, {"name": "nbmail.mjml.body", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.body.html#nbmail.mjml.body", "dispname": "-"}, {"name": "nbmail.mjml.tags.body", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.body.html#nbmail.mjml.body", "dispname": "nbmail.mjml.body"}, {"name": "nbmail.mjml.mj_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_attributes.html#nbmail.mjml.mj_attributes", "dispname": "-"}, {"name": "nbmail.mjml.tags.mj_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_attributes.html#nbmail.mjml.mj_attributes", "dispname": "nbmail.mjml.mj_attributes"}, {"name": "nbmail.mjml.mj_all", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_all.html#nbmail.mjml.mj_all", "dispname": "-"}, {"name": "nbmail.mjml.tags.mj_all", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_all.html#nbmail.mjml.mj_all", "dispname": "nbmail.mjml.mj_all"}, {"name": "nbmail.mjml.mj_class", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_class.html#nbmail.mjml.mj_class", "dispname": "-"}, {"name": "nbmail.mjml.tags.mj_class", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_class.html#nbmail.mjml.mj_class", "dispname": "nbmail.mjml.mj_class"}, {"name": "nbmail.mjml.breakpoint", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.breakpoint.html#nbmail.mjml.breakpoint", "dispname": "-"}, {"name": "nbmail.mjml.tags.breakpoint", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.breakpoint.html#nbmail.mjml.breakpoint", "dispname": "nbmail.mjml.breakpoint"}, {"name": "nbmail.mjml.font", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.font.html#nbmail.mjml.font", "dispname": "-"}, {"name": "nbmail.mjml.tags.font", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.font.html#nbmail.mjml.font", "dispname": "nbmail.mjml.font"}, {"name": "nbmail.mjml.html_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attributes.html#nbmail.mjml.html_attributes", "dispname": "-"}, {"name": "nbmail.mjml.tags.html_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attributes.html#nbmail.mjml.html_attributes", "dispname": "nbmail.mjml.html_attributes"}, {"name": "nbmail.mjml.html_attribute", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attribute.html#nbmail.mjml.html_attribute", "dispname": "-"}, {"name": "nbmail.mjml.tags.html_attribute", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attribute.html#nbmail.mjml.html_attribute", "dispname": "nbmail.mjml.html_attribute"}, {"name": "nbmail.mjml.preview", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.preview.html#nbmail.mjml.preview", "dispname": "-"}, {"name": "nbmail.mjml.tags.preview", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.preview.html#nbmail.mjml.preview", "dispname": "nbmail.mjml.preview"}, {"name": "nbmail.mjml.style", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.style.html#nbmail.mjml.style", "dispname": "-"}, {"name": "nbmail.mjml.tags.style", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.style.html#nbmail.mjml.style", "dispname": "nbmail.mjml.style"}, {"name": "nbmail.mjml.title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.title.html#nbmail.mjml.title", "dispname": "-"}, {"name": "nbmail.mjml.tags.title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.title.html#nbmail.mjml.title", "dispname": "nbmail.mjml.title"}, {"name": "nbmail.mjml.accordion", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion.html#nbmail.mjml.accordion", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion.html#nbmail.mjml.accordion", "dispname": "nbmail.mjml.accordion"}, {"name": "nbmail.mjml.accordion_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_element.html#nbmail.mjml.accordion_element", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_element.html#nbmail.mjml.accordion_element", "dispname": "nbmail.mjml.accordion_element"}, {"name": "nbmail.mjml.accordion_text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_text.html#nbmail.mjml.accordion_text", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion_text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_text.html#nbmail.mjml.accordion_text", "dispname": "nbmail.mjml.accordion_text"}, {"name": "nbmail.mjml.accordion_title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_title.html#nbmail.mjml.accordion_title", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion_title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_title.html#nbmail.mjml.accordion_title", "dispname": "nbmail.mjml.accordion_title"}, {"name": "nbmail.mjml.button", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.button.html#nbmail.mjml.button", "dispname": "-"}, {"name": "nbmail.mjml.tags.button", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.button.html#nbmail.mjml.button", "dispname": "nbmail.mjml.button"}, {"name": "nbmail.mjml.carousel", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel.html#nbmail.mjml.carousel", "dispname": "-"}, {"name": "nbmail.mjml.tags.carousel", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel.html#nbmail.mjml.carousel", "dispname": "nbmail.mjml.carousel"}, {"name": "nbmail.mjml.carousel_image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel_image.html#nbmail.mjml.carousel_image", "dispname": "-"}, {"name": "nbmail.mjml.tags.carousel_image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel_image.html#nbmail.mjml.carousel_image", "dispname": "nbmail.mjml.carousel_image"}, {"name": "nbmail.mjml.column", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.column.html#nbmail.mjml.column", "dispname": "-"}, {"name": "nbmail.mjml.tags.column", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.column.html#nbmail.mjml.column", "dispname": "nbmail.mjml.column"}, {"name": "nbmail.mjml.divider", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.divider.html#nbmail.mjml.divider", "dispname": "-"}, {"name": "nbmail.mjml.tags.divider", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.divider.html#nbmail.mjml.divider", "dispname": "nbmail.mjml.divider"}, {"name": "nbmail.mjml.group", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.group.html#nbmail.mjml.group", "dispname": "-"}, {"name": "nbmail.mjml.tags.group", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.group.html#nbmail.mjml.group", "dispname": "nbmail.mjml.group"}, {"name": "nbmail.mjml.hero", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.hero.html#nbmail.mjml.hero", "dispname": "-"}, {"name": "nbmail.mjml.tags.hero", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.hero.html#nbmail.mjml.hero", "dispname": "nbmail.mjml.hero"}, {"name": "nbmail.mjml.image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.image.html#nbmail.mjml.image", "dispname": "-"}, {"name": "nbmail.mjml.tags.image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.image.html#nbmail.mjml.image", "dispname": "nbmail.mjml.image"}, {"name": "nbmail.mjml.navbar", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar.html#nbmail.mjml.navbar", "dispname": "-"}, {"name": "nbmail.mjml.tags.navbar", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar.html#nbmail.mjml.navbar", "dispname": "nbmail.mjml.navbar"}, {"name": "nbmail.mjml.navbar_link", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar_link.html#nbmail.mjml.navbar_link", "dispname": "-"}, {"name": "nbmail.mjml.tags.navbar_link", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar_link.html#nbmail.mjml.navbar_link", "dispname": "nbmail.mjml.navbar_link"}, {"name": "nbmail.mjml.raw", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.raw.html#nbmail.mjml.raw", "dispname": "-"}, {"name": "nbmail.mjml.tags.raw", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.raw.html#nbmail.mjml.raw", "dispname": "nbmail.mjml.raw"}, {"name": "nbmail.mjml.section", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.section.html#nbmail.mjml.section", "dispname": "-"}, {"name": "nbmail.mjml.tags.section", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.section.html#nbmail.mjml.section", "dispname": "nbmail.mjml.section"}, {"name": "nbmail.mjml.social", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social.html#nbmail.mjml.social", "dispname": "-"}, {"name": "nbmail.mjml.tags.social", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social.html#nbmail.mjml.social", "dispname": "nbmail.mjml.social"}, {"name": "nbmail.mjml.social_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social_element.html#nbmail.mjml.social_element", "dispname": "-"}, {"name": "nbmail.mjml.tags.social_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social_element.html#nbmail.mjml.social_element", "dispname": "nbmail.mjml.social_element"}, {"name": "nbmail.mjml.spacer", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.spacer.html#nbmail.mjml.spacer", "dispname": "-"}, {"name": "nbmail.mjml.tags.spacer", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.spacer.html#nbmail.mjml.spacer", "dispname": "nbmail.mjml.spacer"}, {"name": "nbmail.mjml.table", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.table.html#nbmail.mjml.table", "dispname": "-"}, {"name": "nbmail.mjml.tags.table", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.table.html#nbmail.mjml.table", "dispname": "nbmail.mjml.table"}, {"name": "nbmail.mjml.text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.text.html#nbmail.mjml.text", "dispname": "-"}, {"name": "nbmail.mjml.tags.text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.text.html#nbmail.mjml.text", "dispname": "nbmail.mjml.text"}, {"name": "nbmail.mjml.wrapper", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.wrapper.html#nbmail.mjml.wrapper", "dispname": "-"}, {"name": "nbmail.mjml.tags.wrapper", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.wrapper.html#nbmail.mjml.wrapper", "dispname": "nbmail.mjml.wrapper"}]} +{"project": "nbmail", "version": "0.0.9999", "count": 106, "items": [{"name": "nbmail.Email.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.Email.preview_send_email.html#nbmail.Email.preview_send_email", "dispname": "-"}, {"name": "nbmail.structs.Email.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.Email.preview_send_email.html#nbmail.Email.preview_send_email", "dispname": "nbmail.Email.preview_send_email"}, {"name": "nbmail.Email.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.Email.write_email_message.html#nbmail.Email.write_email_message", "dispname": "-"}, {"name": "nbmail.structs.Email.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.Email.write_email_message.html#nbmail.Email.write_email_message", "dispname": "nbmail.Email.write_email_message"}, {"name": "nbmail.Email.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.Email.write_preview_email.html#nbmail.Email.write_preview_email", "dispname": "-"}, {"name": "nbmail.structs.Email.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/nbmail.Email.write_preview_email.html#nbmail.Email.write_preview_email", "dispname": "nbmail.Email.write_preview_email"}, {"name": "nbmail.Email", "domain": "py", "role": "class", "priority": "1", "uri": "reference/Email.html#nbmail.Email", "dispname": "-"}, {"name": "nbmail.structs.Email", "domain": "py", "role": "class", "priority": "1", "uri": "reference/Email.html#nbmail.Email", "dispname": "nbmail.Email"}, {"name": "nbmail.Email.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/Email.write_preview_email.html#nbmail.Email.write_preview_email", "dispname": "-"}, {"name": "nbmail.structs.Email.write_preview_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/Email.write_preview_email.html#nbmail.Email.write_preview_email", "dispname": "nbmail.Email.write_preview_email"}, {"name": "nbmail.Email.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/Email.write_email_message.html#nbmail.Email.write_email_message", "dispname": "-"}, {"name": "nbmail.structs.Email.write_email_message", "domain": "py", "role": "function", "priority": "1", "uri": "reference/Email.write_email_message.html#nbmail.Email.write_email_message", "dispname": "nbmail.Email.write_email_message"}, {"name": "nbmail.Email.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/Email.preview_send_email.html#nbmail.Email.preview_send_email", "dispname": "-"}, {"name": "nbmail.structs.Email.preview_send_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/Email.preview_send_email.html#nbmail.Email.preview_send_email", "dispname": "nbmail.Email.preview_send_email"}, {"name": "nbmail.quarto_json_to_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/quarto_json_to_email.html#nbmail.quarto_json_to_email", "dispname": "-"}, {"name": "nbmail.ingress.quarto_json_to_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/quarto_json_to_email.html#nbmail.quarto_json_to_email", "dispname": "nbmail.quarto_json_to_email"}, {"name": "nbmail.mjml_to_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml_to_email.html#nbmail.mjml_to_email", "dispname": "-"}, {"name": "nbmail.ingress.mjml_to_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml_to_email.html#nbmail.mjml_to_email", "dispname": "nbmail.mjml_to_email"}, {"name": "nbmail.redmail_to_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/redmail_to_email.html#nbmail.redmail_to_email", "dispname": "-"}, {"name": "nbmail.ingress.redmail_to_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/redmail_to_email.html#nbmail.redmail_to_email", "dispname": "nbmail.redmail_to_email"}, {"name": "nbmail.yagmail_to_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/yagmail_to_email.html#nbmail.yagmail_to_email", "dispname": "-"}, {"name": "nbmail.ingress.yagmail_to_email", "domain": "py", "role": "function", "priority": "1", "uri": "reference/yagmail_to_email.html#nbmail.yagmail_to_email", "dispname": "nbmail.yagmail_to_email"}, {"name": "nbmail.send_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_gmail.html#nbmail.send_email_with_gmail", "dispname": "-"}, {"name": "nbmail.egress.send_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_gmail.html#nbmail.send_email_with_gmail", "dispname": "nbmail.send_email_with_gmail"}, {"name": "nbmail.send_email_with_smtp", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_smtp.html#nbmail.send_email_with_smtp", "dispname": "-"}, {"name": "nbmail.egress.send_email_with_smtp", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_smtp.html#nbmail.send_email_with_smtp", "dispname": "nbmail.send_email_with_smtp"}, {"name": "nbmail.send_email_with_redmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_redmail.html#nbmail.send_email_with_redmail", "dispname": "-"}, {"name": "nbmail.egress.send_email_with_redmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_redmail.html#nbmail.send_email_with_redmail", "dispname": "nbmail.send_email_with_redmail"}, {"name": "nbmail.send_email_with_yagmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_yagmail.html#nbmail.send_email_with_yagmail", "dispname": "-"}, {"name": "nbmail.egress.send_email_with_yagmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_yagmail.html#nbmail.send_email_with_yagmail", "dispname": "nbmail.send_email_with_yagmail"}, {"name": "nbmail.send_email_with_mailgun", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_mailgun.html#nbmail.send_email_with_mailgun", "dispname": "-"}, {"name": "nbmail.egress.send_email_with_mailgun", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_email_with_mailgun.html#nbmail.send_email_with_mailgun", "dispname": "nbmail.send_email_with_mailgun"}, {"name": "nbmail.send_quarto_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_quarto_email_with_gmail.html#nbmail.send_quarto_email_with_gmail", "dispname": "-"}, {"name": "nbmail.egress.send_quarto_email_with_gmail", "domain": "py", "role": "function", "priority": "1", "uri": "reference/send_quarto_email_with_gmail.html#nbmail.send_quarto_email_with_gmail", "dispname": "nbmail.send_quarto_email_with_gmail"}, {"name": "nbmail.write_email_message_to_file", "domain": "py", "role": "function", "priority": "1", "uri": "reference/write_email_message_to_file.html#nbmail.write_email_message_to_file", "dispname": "-"}, {"name": "nbmail.utils.write_email_message_to_file", "domain": "py", "role": "function", "priority": "1", "uri": "reference/write_email_message_to_file.html#nbmail.write_email_message_to_file", "dispname": "nbmail.write_email_message_to_file"}, {"name": "nbmail.mjml.mjml", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mjml.html#nbmail.mjml.mjml", "dispname": "-"}, {"name": "nbmail.mjml.tags.mjml", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mjml.html#nbmail.mjml.mjml", "dispname": "nbmail.mjml.mjml"}, {"name": "nbmail.mjml.head", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.head.html#nbmail.mjml.head", "dispname": "-"}, {"name": "nbmail.mjml.tags.head", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.head.html#nbmail.mjml.head", "dispname": "nbmail.mjml.head"}, {"name": "nbmail.mjml.body", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.body.html#nbmail.mjml.body", "dispname": "-"}, {"name": "nbmail.mjml.tags.body", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.body.html#nbmail.mjml.body", "dispname": "nbmail.mjml.body"}, {"name": "nbmail.mjml.mj_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_attributes.html#nbmail.mjml.mj_attributes", "dispname": "-"}, {"name": "nbmail.mjml.tags.mj_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_attributes.html#nbmail.mjml.mj_attributes", "dispname": "nbmail.mjml.mj_attributes"}, {"name": "nbmail.mjml.mj_all", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_all.html#nbmail.mjml.mj_all", "dispname": "-"}, {"name": "nbmail.mjml.tags.mj_all", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_all.html#nbmail.mjml.mj_all", "dispname": "nbmail.mjml.mj_all"}, {"name": "nbmail.mjml.mj_class", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_class.html#nbmail.mjml.mj_class", "dispname": "-"}, {"name": "nbmail.mjml.tags.mj_class", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.mj_class.html#nbmail.mjml.mj_class", "dispname": "nbmail.mjml.mj_class"}, {"name": "nbmail.mjml.breakpoint", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.breakpoint.html#nbmail.mjml.breakpoint", "dispname": "-"}, {"name": "nbmail.mjml.tags.breakpoint", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.breakpoint.html#nbmail.mjml.breakpoint", "dispname": "nbmail.mjml.breakpoint"}, {"name": "nbmail.mjml.font", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.font.html#nbmail.mjml.font", "dispname": "-"}, {"name": "nbmail.mjml.tags.font", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.font.html#nbmail.mjml.font", "dispname": "nbmail.mjml.font"}, {"name": "nbmail.mjml.html_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attributes.html#nbmail.mjml.html_attributes", "dispname": "-"}, {"name": "nbmail.mjml.tags.html_attributes", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attributes.html#nbmail.mjml.html_attributes", "dispname": "nbmail.mjml.html_attributes"}, {"name": "nbmail.mjml.html_attribute", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attribute.html#nbmail.mjml.html_attribute", "dispname": "-"}, {"name": "nbmail.mjml.tags.html_attribute", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.html_attribute.html#nbmail.mjml.html_attribute", "dispname": "nbmail.mjml.html_attribute"}, {"name": "nbmail.mjml.preview", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.preview.html#nbmail.mjml.preview", "dispname": "-"}, {"name": "nbmail.mjml.tags.preview", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.preview.html#nbmail.mjml.preview", "dispname": "nbmail.mjml.preview"}, {"name": "nbmail.mjml.style", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.style.html#nbmail.mjml.style", "dispname": "-"}, {"name": "nbmail.mjml.tags.style", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.style.html#nbmail.mjml.style", "dispname": "nbmail.mjml.style"}, {"name": "nbmail.mjml.title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.title.html#nbmail.mjml.title", "dispname": "-"}, {"name": "nbmail.mjml.tags.title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.title.html#nbmail.mjml.title", "dispname": "nbmail.mjml.title"}, {"name": "nbmail.mjml.accordion", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion.html#nbmail.mjml.accordion", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion.html#nbmail.mjml.accordion", "dispname": "nbmail.mjml.accordion"}, {"name": "nbmail.mjml.accordion_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_element.html#nbmail.mjml.accordion_element", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_element.html#nbmail.mjml.accordion_element", "dispname": "nbmail.mjml.accordion_element"}, {"name": "nbmail.mjml.accordion_text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_text.html#nbmail.mjml.accordion_text", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion_text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_text.html#nbmail.mjml.accordion_text", "dispname": "nbmail.mjml.accordion_text"}, {"name": "nbmail.mjml.accordion_title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_title.html#nbmail.mjml.accordion_title", "dispname": "-"}, {"name": "nbmail.mjml.tags.accordion_title", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.accordion_title.html#nbmail.mjml.accordion_title", "dispname": "nbmail.mjml.accordion_title"}, {"name": "nbmail.mjml.button", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.button.html#nbmail.mjml.button", "dispname": "-"}, {"name": "nbmail.mjml.tags.button", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.button.html#nbmail.mjml.button", "dispname": "nbmail.mjml.button"}, {"name": "nbmail.mjml.carousel", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel.html#nbmail.mjml.carousel", "dispname": "-"}, {"name": "nbmail.mjml.tags.carousel", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel.html#nbmail.mjml.carousel", "dispname": "nbmail.mjml.carousel"}, {"name": "nbmail.mjml.carousel_image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel_image.html#nbmail.mjml.carousel_image", "dispname": "-"}, {"name": "nbmail.mjml.tags.carousel_image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.carousel_image.html#nbmail.mjml.carousel_image", "dispname": "nbmail.mjml.carousel_image"}, {"name": "nbmail.mjml.column", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.column.html#nbmail.mjml.column", "dispname": "-"}, {"name": "nbmail.mjml.tags.column", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.column.html#nbmail.mjml.column", "dispname": "nbmail.mjml.column"}, {"name": "nbmail.mjml.divider", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.divider.html#nbmail.mjml.divider", "dispname": "-"}, {"name": "nbmail.mjml.tags.divider", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.divider.html#nbmail.mjml.divider", "dispname": "nbmail.mjml.divider"}, {"name": "nbmail.mjml.group", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.group.html#nbmail.mjml.group", "dispname": "-"}, {"name": "nbmail.mjml.tags.group", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.group.html#nbmail.mjml.group", "dispname": "nbmail.mjml.group"}, {"name": "nbmail.mjml.hero", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.hero.html#nbmail.mjml.hero", "dispname": "-"}, {"name": "nbmail.mjml.tags.hero", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.hero.html#nbmail.mjml.hero", "dispname": "nbmail.mjml.hero"}, {"name": "nbmail.mjml.image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.image.html#nbmail.mjml.image", "dispname": "-"}, {"name": "nbmail.mjml.tags.image", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.image.html#nbmail.mjml.image", "dispname": "nbmail.mjml.image"}, {"name": "nbmail.mjml.navbar", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar.html#nbmail.mjml.navbar", "dispname": "-"}, {"name": "nbmail.mjml.tags.navbar", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar.html#nbmail.mjml.navbar", "dispname": "nbmail.mjml.navbar"}, {"name": "nbmail.mjml.navbar_link", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar_link.html#nbmail.mjml.navbar_link", "dispname": "-"}, {"name": "nbmail.mjml.tags.navbar_link", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.navbar_link.html#nbmail.mjml.navbar_link", "dispname": "nbmail.mjml.navbar_link"}, {"name": "nbmail.mjml.raw", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.raw.html#nbmail.mjml.raw", "dispname": "-"}, {"name": "nbmail.mjml.tags.raw", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.raw.html#nbmail.mjml.raw", "dispname": "nbmail.mjml.raw"}, {"name": "nbmail.mjml.section", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.section.html#nbmail.mjml.section", "dispname": "-"}, {"name": "nbmail.mjml.tags.section", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.section.html#nbmail.mjml.section", "dispname": "nbmail.mjml.section"}, {"name": "nbmail.mjml.social", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social.html#nbmail.mjml.social", "dispname": "-"}, {"name": "nbmail.mjml.tags.social", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social.html#nbmail.mjml.social", "dispname": "nbmail.mjml.social"}, {"name": "nbmail.mjml.social_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social_element.html#nbmail.mjml.social_element", "dispname": "-"}, {"name": "nbmail.mjml.tags.social_element", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.social_element.html#nbmail.mjml.social_element", "dispname": "nbmail.mjml.social_element"}, {"name": "nbmail.mjml.spacer", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.spacer.html#nbmail.mjml.spacer", "dispname": "-"}, {"name": "nbmail.mjml.tags.spacer", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.spacer.html#nbmail.mjml.spacer", "dispname": "nbmail.mjml.spacer"}, {"name": "nbmail.mjml.table", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.table.html#nbmail.mjml.table", "dispname": "-"}, {"name": "nbmail.mjml.tags.table", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.table.html#nbmail.mjml.table", "dispname": "nbmail.mjml.table"}, {"name": "nbmail.mjml.text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.text.html#nbmail.mjml.text", "dispname": "-"}, {"name": "nbmail.mjml.tags.text", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.text.html#nbmail.mjml.text", "dispname": "nbmail.mjml.text"}, {"name": "nbmail.mjml.wrapper", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.wrapper.html#nbmail.mjml.wrapper", "dispname": "-"}, {"name": "nbmail.mjml.tags.wrapper", "domain": "py", "role": "function", "priority": "1", "uri": "reference/mjml.wrapper.html#nbmail.mjml.wrapper", "dispname": "nbmail.mjml.wrapper"}]} diff --git a/docs/summary.quarto_ipynb b/docs/summary.quarto_ipynb index 31b113c..d12aa5d 100644 --- a/docs/summary.quarto_ipynb +++ b/docs/summary.quarto_ipynb @@ -21,7 +21,7 @@ "\n", "In this tutorial, we'll walk through the whole game of sending email. We'll start with this simple example:\n" ], - "id": "14101fd1" + "id": "a59ad40b" }, { "cell_type": "code", @@ -54,7 +54,7 @@ " html=email_body,\n", ")" ], - "id": "3e29c5ba", + "id": "1e722fc3", "execution_count": null, "outputs": [] }, @@ -78,7 +78,7 @@ "* Authenticate (may need to refer to its own authentication page in guide)\n", "* Send\n" ], - "id": "31ca0b47" + "id": "466f45ac" }, { "cell_type": "code", @@ -111,7 +111,7 @@ " html=email_body,\n", ")" ], - "id": "ecc38edf", + "id": "d7f3dc30", "execution_count": null, "outputs": [] }, @@ -184,7 +184,7 @@ "\n", "Check out the email content we will send.\n" ], - "id": "840912f2" + "id": "a0472e78" }, { "cell_type": "code", @@ -194,7 +194,7 @@ "\n", "sp500.head(10).style" ], - "id": "0cda1fb2", + "id": "b0858409", "execution_count": null, "outputs": [] }, @@ -204,7 +204,7 @@ "source": [ "And now we send the email!\n" ], - "id": "f44aff8c" + "id": "e696c7a5" }, { "cell_type": "code", @@ -223,7 +223,7 @@ " text=email_plaintext,\n", ")" ], - "id": "4ad22022", + "id": "9fbe68e8", "execution_count": null, "outputs": [] }, @@ -235,7 +235,7 @@ "Explain why email_plaintext is there?\n", "-->" ], - "id": "15ee0056" + "id": "39984027" } ], "metadata": { diff --git a/nbmail/__init__.py b/nbmail/__init__.py index dc25a87..8c933b1 100644 --- a/nbmail/__init__.py +++ b/nbmail/__init__.py @@ -1,35 +1,35 @@ from .ingress import ( - redmail_to_intermediate_email, - yagmail_to_intermediate_email, - mjml_to_intermediate_email, - quarto_json_to_intermediate_email, + redmail_to_email, + yagmail_to_email, + mjml_to_email, + quarto_json_to_email, ) from .egress import ( send_quarto_email_with_gmail, - send_intermediate_email_with_gmail, - send_intermediate_email_with_redmail, - send_intermediate_email_with_yagmail, - send_intermediate_email_with_mailgun, - send_intermediate_email_with_smtp, + send_email_with_gmail, + send_email_with_redmail, + send_email_with_yagmail, + send_email_with_mailgun, + send_email_with_smtp, ) from .utils import write_email_message_to_file -from .structs import IntermediateEmail +from .structs import Email __all__ = [ - "quarto_json_to_intermediate_email", - "IntermediateEmail", - "redmail_to_intermediate_email", - "yagmail_to_intermediate_email", - "mjml_to_intermediate_email", + "quarto_json_to_email", + "Email", + "redmail_to_email", + "yagmail_to_email", + "mjml_to_email", "send_quarto_email_with_gmail", - "send_intermediate_email_with_gmail", - "send_intermediate_email_with_redmail", - "send_intermediate_email_with_yagmail", - "send_intermediate_email_with_mailgun", - "send_intermediate_email_with_smtp", + "send_email_with_gmail", + "send_email_with_redmail", + "send_email_with_yagmail", + "send_email_with_mailgun", + "send_email_with_smtp", "write_email_message_to_file", ] diff --git a/nbmail/egress.py b/nbmail/egress.py index 8ce18aa..ba8ec70 100644 --- a/nbmail/egress.py +++ b/nbmail/egress.py @@ -12,18 +12,18 @@ from email import encoders from typing import Literal -from .ingress import quarto_json_to_intermediate_email +from .ingress import quarto_json_to_email -from .structs import IntermediateEmail +from .structs import Email import warnings __all__ = [ "send_quarto_email_with_gmail", - "send_intermediate_email_with_gmail", - "send_intermediate_email_with_redmail", - "send_intermediate_email_with_yagmail", - "send_intermediate_email_with_mailgun", - "send_intermediate_email_with_smtp", + "send_email_with_gmail", + "send_email_with_redmail", + "send_email_with_yagmail", + "send_email_with_mailgun", + "send_email_with_smtp", ] @@ -68,9 +68,9 @@ def send_quarto_email_with_gmail( ) ``` """ - i_email: IntermediateEmail = quarto_json_to_intermediate_email(json_path) + i_email: Email = quarto_json_to_email(json_path) i_email.recipients = recipients - send_intermediate_email_with_gmail( + send_email_with_gmail( username=username, password=password, i_email=i_email ) @@ -79,11 +79,11 @@ def send_quarto_email_with_gmail( # Could also take creds object -def send_intermediate_email_with_gmail( - username: str, password: str, i_email: IntermediateEmail +def send_email_with_gmail( + username: str, password: str, i_email: Email ): """ - Send an Intermediate Email object via Gmail. + Send an Email object via Gmail. Parameters ---------- @@ -94,7 +94,7 @@ def send_intermediate_email_with_gmail( Gmail app password i_email - IntermediateEmail object containing the email content and attachments + Email object containing the email content and attachments Returns ------- @@ -104,17 +104,17 @@ def send_intermediate_email_with_gmail( Examples -------- ```python - email = IntermediateEmail( + email = Email( html="

Hello world

", subject="Test Email", recipients=["user@example.com"], ) - send_intermediate_email_with_gmail("user@gmail.com", "password123", email) + send_email_with_gmail("user@gmail.com", "password123", email) ``` """ # Compose the email - return send_intermediate_email_with_smtp( + return send_email_with_smtp( smtp_host="smtp.gmail.com", smtp_port=587, username=username, @@ -124,14 +124,14 @@ def send_intermediate_email_with_gmail( ) -def send_intermediate_email_with_redmail(i_email: IntermediateEmail): +def send_email_with_redmail(i_email: Email): """ - Send an Intermediate Email object via Redmail. + Send an Email object via Redmail. Parameters ---------- i_email - IntermediateEmail object containing the email content and attachments + Email object containing the email content and attachments Returns ------- @@ -144,14 +144,14 @@ def send_intermediate_email_with_redmail(i_email: IntermediateEmail): raise NotImplementedError -def send_intermediate_email_with_yagmail(i_email: IntermediateEmail): +def send_email_with_yagmail(i_email: Email): """ - Send an Intermediate Email object via Yagmail. + Send an Email object via Yagmail. Parameters ---------- i_email - IntermediateEmail object containing the email content and attachments + Email object containing the email content and attachments Returns ------- @@ -165,14 +165,14 @@ def send_intermediate_email_with_yagmail(i_email: IntermediateEmail): raise NotImplementedError -def send_intermediate_email_with_mailgun( +def send_email_with_mailgun( api_key: str, domain: str, sender: str, - i_email: IntermediateEmail, + i_email: Email, ): """ - Send an Intermediate Email object via Mailgun. + Send an Email object via Mailgun. Parameters ---------- @@ -183,7 +183,7 @@ def send_intermediate_email_with_mailgun( sender Email address to send from (must be authorized in your domain) i_email - IntermediateEmail object containing the email content and attachments + Email object containing the email content and attachments Returns ------- @@ -198,13 +198,13 @@ def send_intermediate_email_with_mailgun( Examples -------- ```python - email = IntermediateEmail( + email = Email( html="

Hello world

", subject="Test Email", recipients=["user@example.com"], ) - response = send_intermediate_email_with_mailgun( + response = send_email_with_mailgun( api_key="your-api-key", domain="mg.yourdomain.com", sender="noreply@yourdomain.com", @@ -265,16 +265,16 @@ def send_intermediate_email_with_mailgun( return response -def send_intermediate_email_with_smtp( +def send_email_with_smtp( smtp_host: str, smtp_port: int, username: str, password: str, - i_email: IntermediateEmail, + i_email: Email, security: str = Literal["tls", "ssl", "smtp"], ): """ - Send an Intermediate Email object via SMTP. + Send an Email object via SMTP. Parameters ---------- @@ -291,7 +291,7 @@ def send_intermediate_email_with_smtp( SMTP account password i_email - IntermediateEmail object containing the email content and attachments + Email object containing the email content and attachments security Security protocol to use: "tls" (STARTTLS), "ssl" (SSL/TLS), or "smtp" (plain SMTP). @@ -310,14 +310,14 @@ def send_intermediate_email_with_smtp( Examples -------- ```python - email = IntermediateEmail( + email = Email( html="

Hello world

", subject="Test Email", recipients=["user@example.com"], ) # TLS connection (port 587) - recommended - send_intermediate_email_with_smtp( + send_email_with_smtp( "smtp.example.com", 587, "user@example.com", @@ -327,7 +327,7 @@ def send_intermediate_email_with_smtp( ) # SSL connection (port 465) - send_intermediate_email_with_smtp( + send_email_with_smtp( "smtp.example.com", 465, "user@example.com", @@ -337,7 +337,7 @@ def send_intermediate_email_with_smtp( ) # Plain SMTP (port 25) - insecure, for testing only - send_intermediate_email_with_smtp( + send_email_with_smtp( "127.0.0.1", 8025, "test@example.com", diff --git a/nbmail/ingress.py b/nbmail/ingress.py index e92e09a..58b43aa 100644 --- a/nbmail/ingress.py +++ b/nbmail/ingress.py @@ -5,22 +5,22 @@ from email.message import EmailMessage from mjml import mjml2html -from .structs import IntermediateEmail +from .structs import Email from .mjml import MJMLTag from .mjml.image_processor import _process_mjml_images import warnings __all__ = [ - "redmail_to_intermediate_email", - "yagmail_to_intermediate_email", - "mjml_to_intermediate_email", - "quarto_json_to_intermediate_email", + "redmail_to_email", + "yagmail_to_email", + "mjml_to_email", + "quarto_json_to_email", ] -def redmail_to_intermediate_email(msg: EmailMessage) -> IntermediateEmail: +def redmail_to_email(msg: EmailMessage) -> Email: """ - Convert a Redmail EmailMessage object to an IntermediateEmail + Convert a Redmail EmailMessage object to an Email Params ------ @@ -29,12 +29,12 @@ def redmail_to_intermediate_email(msg: EmailMessage) -> IntermediateEmail: Converts the input EmailMessage to the intermediate email structure """ - return _email_message_to_intermediate_email(msg) + return _email_message_to_email(msg) -def yagmail_to_intermediate_email(): +def yagmail_to_email(): """ - Convert a Yagmail email object to an IntermediateEmail + Convert a Yagmail email object to an Email Params ------ @@ -45,11 +45,11 @@ def yagmail_to_intermediate_email(): pass -def mjml_to_intermediate_email( +def mjml_to_email( mjml_content: str | MJMLTag, -) -> IntermediateEmail: +) -> Email: """ - Convert MJML markup to an IntermediateEmail + Convert MJML markup to an Email Parameters ---------- @@ -58,7 +58,7 @@ def mjml_to_intermediate_email( Returns ------ - An Intermediate Email object + An Email object """ # Handle MJMLTag objects by preprocessing images @@ -73,7 +73,7 @@ def mjml_to_intermediate_email( email_content = mjml2html(mjml_markup) - i_email = IntermediateEmail( + i_email = Email( html=email_content, subject="", rsc_email_supress_report_attachment=False, @@ -85,9 +85,9 @@ def mjml_to_intermediate_email( # useful because redmail bundles an email message... may help in other cases too -def _email_message_to_intermediate_email(msg: EmailMessage) -> IntermediateEmail: +def _email_message_to_email(msg: EmailMessage) -> Email: """ - Convert a Python EmailMessage object to an IntermediateEmail + Convert a Python EmailMessage object to an Email Parameters ------ @@ -147,7 +147,7 @@ def _email_message_to_intermediate_email(msg: EmailMessage) -> IntermediateEmail # Not certain that all attached files have associated filenames external_attachments.append(filename) - return IntermediateEmail( + return Email( html=html or "", subject=subject, external_attachments=external_attachments if external_attachments else None, @@ -158,9 +158,9 @@ def _email_message_to_intermediate_email(msg: EmailMessage) -> IntermediateEmail # Helper method to parse the quarto JSON -def quarto_json_to_intermediate_email(path: str) -> IntermediateEmail: +def quarto_json_to_email(path: str) -> Email: """ - Convert a Quarto output metadata JSON file to an IntermediateEmail + Convert a Quarto output metadata JSON file to an Email Parameters ------ @@ -190,7 +190,7 @@ def quarto_json_to_intermediate_email(path: str) -> IntermediateEmail: ) supress_scheduled = metadata.get("rsc_email_supress_scheduled", False) - i_email = IntermediateEmail( + i_email = Email( html=email_html, text=email_text, inline_attachments=email_images, diff --git a/nbmail/mjml/__init__.py b/nbmail/mjml/__init__.py index ea3b2f1..3720161 100644 --- a/nbmail/mjml/__init__.py +++ b/nbmail/mjml/__init__.py @@ -39,7 +39,7 @@ navbar_link, social_element, ) -# _process_mjml_images is called internally by mjml_to_intermediate_email +# _process_mjml_images is called internally by mjml_to_email __all__ = ( "MJMLTag", diff --git a/nbmail/mjml/_core.py b/nbmail/mjml/_core.py index d55913e..c77a25d 100644 --- a/nbmail/mjml/_core.py +++ b/nbmail/mjml/_core.py @@ -132,7 +132,7 @@ def _to_mjml(self, indent: int = 0, eol: str = "\n") -> str: Ported from htmltools Tag rendering logic. Note: BytesIO/bytes in image src attributes are not supported by _to_mjml(). - Pass the MJMLTag directly to mjml_to_intermediate_email() instead. + Pass the MJMLTag directly to mjml_to_email() instead. """ def _flatten(children): @@ -150,8 +150,8 @@ def _flatten(children): if isinstance(src_value, (bytes, BytesIO)): raise ValueError( "Cannot render MJML with BytesIO/bytes in image src attribute. " - "Pass the MJMLTag object directly to mjml_to_intermediate_email() instead of calling _to_mjml() first. " - "Example: i_email = mjml_to_intermediate_email(doc)" + "Pass the MJMLTag object directly to mjml_to_email() instead of calling _to_mjml() first. " + "Example: i_email = mjml_to_email(doc)" ) # Build attribute string @@ -181,8 +181,8 @@ def _flatten(children): return f"{pad}<{self.tagName}{attr_str}>" def _repr_html_(self): - from ..ingress import mjml_to_intermediate_email - return mjml_to_intermediate_email(self)._repr_html_() + from ..ingress import mjml_to_email + return mjml_to_email(self)._repr_html_() # TODO: make something deliberate def __repr__(self) -> str: @@ -193,7 +193,7 @@ def __repr__(self) -> str: ) return f"" - # warning explain that they are not to pass this to intermediate email + # warning explain that they are not to pass this to email def to_html(self, **mjml2html_kwargs) -> str: """ Render MJMLTag to HTML using mjml2html. @@ -202,7 +202,7 @@ def to_html(self, **mjml2html_kwargs) -> str: in ... with a warning. Note: This method embeds all images as inline data URIs in the HTML. - For email composition with inline attachments, use mjml_to_intermediate_email() instead. + For email composition with inline attachments, use mjml_to_email() instead. Parameters ---------- diff --git a/nbmail/mjml/image_processor.py b/nbmail/mjml/image_processor.py index 4395686..483705f 100644 --- a/nbmail/mjml/image_processor.py +++ b/nbmail/mjml/image_processor.py @@ -52,7 +52,7 @@ def _process_mjml_images(mjml_tag: MJMLTag) -> Tuple[MJMLTag, Dict[str, str]]: Extract inline attachments from MJML tree and convert bytes/BytesIO to CID references. This is a private function. Users should not call it directly. - It is called automatically by mjml_to_intermediate_email(). + It is called automatically by mjml_to_email(). This function recursively walks through the MJML tag tree and finds mj-image tags with BytesIO or bytes in their src attribute. It converts these to CID references @@ -74,7 +74,7 @@ def _process_mjml_images(mjml_tag: MJMLTag) -> Tuple[MJMLTag, Dict[str, str]]: -------- ```python from nbmail.mjml import mjml, body, section, column, image - from nbmail import mjml_to_intermediate_email + from nbmail import mjml_to_email from io import BytesIO # Create BytesIO with image data @@ -95,8 +95,8 @@ def _process_mjml_images(mjml_tag: MJMLTag) -> Tuple[MJMLTag, Dict[str, str]]: ) ) - # Pass directly to mjml_to_intermediate_email (calls _process_mjml_images internally) - i_email = mjml_to_intermediate_email(email) + # Pass directly to mjml_to_email (calls _process_mjml_images internally) + i_email = mjml_to_email(email) # Result: i_email.inline_attachments = {"plot_1.png": "iVBORw0KGgo..."} ``` diff --git a/nbmail/mjml/tests/test_core.py b/nbmail/mjml/tests/test_core.py index 05bcffd..21dbf38 100644 --- a/nbmail/mjml/tests/test_core.py +++ b/nbmail/mjml/tests/test_core.py @@ -1,6 +1,6 @@ import pytest from io import BytesIO -from nbmail.ingress import mjml_to_intermediate_email +from nbmail.ingress import mjml_to_email from nbmail.mjml._core import MJMLTag, TagAttrDict @@ -122,14 +122,14 @@ def test_to_html_warns_and_wraps_other_tags(): assert "html" in html_result -def test_repr_html_returns_intermediate_email_repr_html(): +def test_repr_html_returns_email_repr_html(): tag = MJMLTag("mjml", MJMLTag("mj-body")) html_from_repr = tag._repr_html_() - # _repr_html_() should return the HTML representation from mjml_to_intermediate_email + # _repr_html_() should return the HTML representation from mjml_to_email assert "Hello world

", subject="Test Email", recipients=["user@example.com"], @@ -123,7 +123,7 @@ def _repr_html_(self) -> str: """ Return HTML representation with inline attachments for rich display. - This method enables rich display of the IntermediateEmail in Jupyter notebooks + This method enables rich display of the Email in Jupyter notebooks and other IPython-compatible environments. It converts cid: references to base64 data URIs so the email can be previewed directly in the notebook. @@ -136,7 +136,7 @@ def _repr_html_(self) -> str: -------- ```python # In a Jupyter notebook, simply display the email object: - email = IntermediateEmail( + email = Email( html='

Hello

', subject="Test Email", inline_attachments={"img1.png": "iVBORw0KGgo..."} @@ -188,10 +188,10 @@ def write_preview_email(self, out_file: str = "preview_email.html") -> None: def write_email_message(self) -> EmailMessage: """ - Convert the IntermediateEmail to a Python EmailMessage. + Convert the Email to a Python EmailMessage. This method creates a standard library EmailMessage object from the - IntermediateEmail, including HTML, plain text, recipients, and attachments. + Email, including HTML, plain text, recipients, and attachments. Returns ------- diff --git a/nbmail/tests/test_egress.py b/nbmail/tests/test_egress.py index 26200af..fb98b13 100644 --- a/nbmail/tests/test_egress.py +++ b/nbmail/tests/test_egress.py @@ -3,18 +3,18 @@ import pytest from nbmail.egress import ( - send_intermediate_email_with_redmail, - send_intermediate_email_with_yagmail, - send_intermediate_email_with_mailgun, - send_intermediate_email_with_smtp, - send_intermediate_email_with_gmail, + send_email_with_redmail, + send_email_with_yagmail, + send_email_with_mailgun, + send_email_with_smtp, + send_email_with_gmail, send_quarto_email_with_gmail, ) -from nbmail.structs import IntermediateEmail +from nbmail.structs import Email def make_basic_email(): - return IntermediateEmail( + return Email( html="

Hi

", subject="Test", recipients=["a@example.com"], @@ -38,15 +38,15 @@ def setup_smtp_mocks(monkeypatch): return mock_smtp, mock_smtp_ssl, context -def test_send_intermediate_email_with_gmail_calls_smtp(monkeypatch): +def test_send_email_with_gmail_calls_smtp(monkeypatch): email = make_basic_email() mock_smtp_send = MagicMock() monkeypatch.setattr( - "nbmail.egress.send_intermediate_email_with_smtp", mock_smtp_send + "nbmail.egress.send_email_with_smtp", mock_smtp_send ) - send_intermediate_email_with_gmail("user@gmail.com", "pass", email) + send_email_with_gmail("user@gmail.com", "pass", email) mock_smtp_send.assert_called_once_with( smtp_host="smtp.gmail.com", @@ -58,11 +58,11 @@ def test_send_intermediate_email_with_gmail_calls_smtp(monkeypatch): ) -def test_send_intermediate_email_with_smtp_tls(monkeypatch): +def test_send_email_with_smtp_tls(monkeypatch): email = make_basic_email() mock_smtp, mock_smtp_ssl, context = setup_smtp_mocks(monkeypatch) - send_intermediate_email_with_smtp( + send_email_with_smtp( smtp_host="smtp.example.com", smtp_port=587, username="user", @@ -77,11 +77,11 @@ def test_send_intermediate_email_with_smtp_tls(monkeypatch): context.sendmail.assert_called_once() -def test_send_intermediate_email_with_smtp_ssl(monkeypatch): +def test_send_email_with_smtp_ssl(monkeypatch): email = make_basic_email() mock_smtp, mock_smtp_ssl, context = setup_smtp_mocks(monkeypatch) - send_intermediate_email_with_smtp( + send_email_with_smtp( smtp_host="smtp.example.com", smtp_port=465, username="user", @@ -95,14 +95,14 @@ def test_send_intermediate_email_with_smtp_ssl(monkeypatch): context.sendmail.assert_called_once() -def test_send_intermediate_email_with_smtp_with_attachment(monkeypatch): +def test_send_email_with_smtp_with_attachment(monkeypatch): email = make_basic_email() email.external_attachments = ["file.txt"] mock_smtp, mock_smtp_ssl, context = setup_smtp_mocks(monkeypatch) with patch("builtins.open", mock_open(read_data=b"data")): - send_intermediate_email_with_smtp( + send_email_with_smtp( smtp_host="smtp.example.com", smtp_port=587, username="user", @@ -117,14 +117,14 @@ def test_send_intermediate_email_with_smtp_with_attachment(monkeypatch): assert 'Content-Disposition: attachment; filename="file.txt"' in email_message -def test_send_intermediate_email_with_smtp_unknown_mime_type(monkeypatch): +def test_send_email_with_smtp_unknown_mime_type(monkeypatch): email = make_basic_email() email.external_attachments = ["file_without_extension"] mock_smtp, mock_smtp_ssl, context = setup_smtp_mocks(monkeypatch) with patch("builtins.open", mock_open(read_data=b"data")): - send_intermediate_email_with_smtp( + send_email_with_smtp( smtp_host="smtp.example.com", smtp_port=587, username="user", @@ -144,11 +144,11 @@ def test_send_intermediate_email_with_smtp_unknown_mime_type(monkeypatch): ) -def test_send_intermediate_email_with_smtp_sendmail_args(monkeypatch): +def test_send_email_with_smtp_sendmail_args(monkeypatch): email = make_basic_email() mock_smtp, mock_smtp_ssl, context = setup_smtp_mocks(monkeypatch) - send_intermediate_email_with_smtp( + send_email_with_smtp( smtp_host="mock_host", smtp_port=465, username="user@gmail.com", @@ -175,16 +175,16 @@ def test_send_intermediate_email_with_smtp_sendmail_args(monkeypatch): # this is probably not the best way to test this, # for what it's worth I will test each part separately def test_send_quarto_email_with_gmail(monkeypatch): - # Mock the quarto_json_to_intermediate_email function + # Mock the quarto_json_to_email function mock_quarto_to_email = MagicMock(return_value=make_basic_email()) monkeypatch.setattr( - "nbmail.egress.quarto_json_to_intermediate_email", mock_quarto_to_email + "nbmail.egress.quarto_json_to_email", mock_quarto_to_email ) # Mock the Gmail sending function mock_send_gmail = MagicMock() monkeypatch.setattr( - "nbmail.egress.send_intermediate_email_with_gmail", mock_send_gmail + "nbmail.egress.send_email_with_gmail", mock_send_gmail ) # Call the function @@ -203,7 +203,7 @@ def test_send_quarto_email_with_gmail(monkeypatch): assert i_email.recipients == ["recipient@example.com"] -def test_send_intermediate_email_with_mailgun(monkeypatch): +def test_send_email_with_mailgun(monkeypatch): email = make_basic_email() email.external_attachments = ["file.txt"] @@ -225,7 +225,7 @@ def test_send_intermediate_email_with_mailgun(monkeypatch): with patch("mailgun.client.Client", mock_client_class): with patch("builtins.open", mock_open(read_data=b"file content")): - response = send_intermediate_email_with_mailgun( + response = send_email_with_mailgun( api_key="test-api-key", domain="mg.example.com", sender="sender@example.com", @@ -259,15 +259,15 @@ def test_send_intermediate_email_with_mailgun(monkeypatch): } -def test_send_intermediate_email_with_mailgun_no_recipients(): - email = IntermediateEmail( +def test_send_email_with_mailgun_no_recipients(): + email = Email( html="

Hi

", subject="Test", recipients=None, ) with pytest.raises(TypeError, match="i_email must have a populated recipients attribute"): - send_intermediate_email_with_mailgun( + send_email_with_mailgun( api_key="test-api-key", domain="mg.example.com", sender="sender@example.com", @@ -278,8 +278,8 @@ def test_send_intermediate_email_with_mailgun_no_recipients(): @pytest.mark.parametrize( "send_func", [ - send_intermediate_email_with_redmail, - send_intermediate_email_with_yagmail, + send_email_with_redmail, + send_email_with_yagmail, ], ) def test_not_implemented_functions(send_func): diff --git a/nbmail/tests/test_end_to_end.py b/nbmail/tests/test_end_to_end.py index 42f62fc..29a6175 100644 --- a/nbmail/tests/test_end_to_end.py +++ b/nbmail/tests/test_end_to_end.py @@ -2,8 +2,8 @@ import time from aiosmtpd.controller import Controller from email import message_from_bytes -from nbmail.egress import send_intermediate_email_with_smtp -from nbmail.structs import IntermediateEmail +from nbmail.egress import send_email_with_smtp +from nbmail.structs import Email class EmailHandler: @@ -37,7 +37,7 @@ def smtp_server(): def test_send_email_integration(smtp_server): controller, handler = smtp_server - email = IntermediateEmail( + email = Email( html="

Test Email

Hello World

", subject="Integration Test", recipients=["test@example.com"], @@ -47,7 +47,7 @@ def test_send_email_integration(smtp_server): ) # Send email to the test SMTP server - send_intermediate_email_with_smtp( + send_email_with_smtp( smtp_host="127.0.0.1", smtp_port=8025, username="test@example.com", diff --git a/nbmail/tests/test_ingress.py b/nbmail/tests/test_ingress.py index fea863a..148c4cd 100644 --- a/nbmail/tests/test_ingress.py +++ b/nbmail/tests/test_ingress.py @@ -4,23 +4,23 @@ from base64 import b64encode from nbmail.ingress import ( - redmail_to_intermediate_email, - yagmail_to_intermediate_email, - mjml_to_intermediate_email, - quarto_json_to_intermediate_email, - _email_message_to_intermediate_email, + redmail_to_email, + yagmail_to_email, + mjml_to_email, + quarto_json_to_email, + _email_message_to_email, ) -from nbmail.structs import IntermediateEmail +from nbmail.structs import Email -def test_email_message_to_intermediate_email_simple(): +def test_email_message_to_email_simple(): msg = EmailMessage() msg["Subject"] = "Test Subject" msg["To"] = "recipient@example.com" msg.set_content("Plain text") msg.add_alternative("

HTML content

", subtype="html") - result = _email_message_to_intermediate_email(msg) + result = _email_message_to_email(msg) assert result.subject == "Test Subject" assert result.recipients == ["recipient@example.com"] @@ -30,7 +30,7 @@ def test_email_message_to_intermediate_email_simple(): assert result.external_attachments is None -def test_email_message_to_intermediate_email_multiple_recipients(): +def test_email_message_to_email_multiple_recipients(): msg = EmailMessage() msg["Subject"] = "Multi-recipient" msg["To"] = "to1@example.com, to2@example.com" @@ -38,7 +38,7 @@ def test_email_message_to_intermediate_email_multiple_recipients(): msg["Bcc"] = "bcc@example.com" msg.add_alternative("Test", subtype="html") - result = _email_message_to_intermediate_email(msg) + result = _email_message_to_email(msg) assert len(result.recipients) == 4 assert "to1@example.com" in result.recipients @@ -47,7 +47,7 @@ def test_email_message_to_intermediate_email_multiple_recipients(): assert "bcc@example.com" in result.recipients -def test_email_message_to_intermediate_email_with_inline_image(): +def test_email_message_to_email_with_inline_image(): msg = EmailMessage() msg["Subject"] = "With Image" msg.add_alternative("", subtype="html") @@ -56,65 +56,65 @@ def test_email_message_to_intermediate_email_with_inline_image(): img_data = b"\x89PNG\r\n\x1a\n" msg.add_attachment(img_data, maintype="image", subtype="png", cid="img1") - result = _email_message_to_intermediate_email(msg) + result = _email_message_to_email(msg) assert result.inline_attachments is not None assert "img1" in result.inline_attachments assert result.inline_attachments["img1"] == b64encode(img_data).decode("utf-8") -def test_email_message_to_intermediate_email_with_external_attachment(): +def test_email_message_to_email_with_external_attachment(): msg = EmailMessage() msg["Subject"] = "With Attachment" msg.add_alternative("Content", subtype="html") msg.add_attachment(b"file content", maintype="application", subtype="pdf", filename="document.pdf") - result = _email_message_to_intermediate_email(msg) + result = _email_message_to_email(msg) assert result.external_attachments is not None assert "document.pdf" in result.external_attachments -def test_email_message_to_intermediate_email_plain_text_only(): +def test_email_message_to_email_plain_text_only(): msg = EmailMessage() msg["Subject"] = "Plain Only" msg.set_content("Just plain text") - result = _email_message_to_intermediate_email(msg) + result = _email_message_to_email(msg) assert result.text == "Just plain text\n" assert result.html == "" # Empty string when no HTML -def test_email_message_to_intermediate_email_html_only_not_multipart(): +def test_email_message_to_email_html_only_not_multipart(): msg = EmailMessage() msg["Subject"] = "HTML Only" msg.set_content("HTML", subtype="html") - result = _email_message_to_intermediate_email(msg) + result = _email_message_to_email(msg) assert result.html == "HTML\n" assert result.text is None -def test_redmail_to_intermediate_email(): +def test_redmail_to_email(): msg = EmailMessage() msg["Subject"] = "Redmail Test" msg.add_alternative("Redmail content", subtype="html") - result = redmail_to_intermediate_email(msg) + result = redmail_to_email(msg) - assert isinstance(result, IntermediateEmail) + assert isinstance(result, Email) assert result.subject == "Redmail Test" assert "Redmail content" in result.html -def test_yagmail_to_intermediate_email_not_implemented(): - result = yagmail_to_intermediate_email() +def test_yagmail_to_email_not_implemented(): + result = yagmail_to_email() assert result is None -def test_mjml_to_intermediate_email_no_images(): +def test_mjml_to_email_no_images(): mjml_content = """ @@ -127,15 +127,15 @@ def test_mjml_to_intermediate_email_no_images(): """ - result = mjml_to_intermediate_email(mjml_content) + result = mjml_to_email(mjml_content) - assert isinstance(result, IntermediateEmail) + assert isinstance(result, Email) assert "Hello World" in result.html assert result.subject == "" assert result.inline_attachments == {} -def test_mjml_to_intermediate_email_with_string_url(): +def test_mjml_to_email_with_string_url(): mjml_content = """ @@ -148,14 +148,14 @@ def test_mjml_to_intermediate_email_with_string_url(): """ - result = mjml_to_intermediate_email(mjml_content) + result = mjml_to_email(mjml_content) - assert isinstance(result, IntermediateEmail) + assert isinstance(result, Email) assert result.inline_attachments == {} assert "https://example.com/image.jpg" in result.html -def test_mjml_to_intermediate_email_with_bytesio(): +def test_mjml_to_email_with_bytesio(): from io import BytesIO from nbmail.mjml import mjml, body, section, column, image @@ -175,9 +175,9 @@ def test_mjml_to_intermediate_email_with_bytesio(): ) ) - result = mjml_to_intermediate_email(mjml_tag) + result = mjml_to_email(mjml_tag) - assert isinstance(result, IntermediateEmail) + assert isinstance(result, Email) assert len(result.inline_attachments) == 1 cid_filename = list(result.inline_attachments.keys())[0] @@ -211,13 +211,13 @@ def test_mjml_to_mjml_with_bytesio_raises_error(): with pytest.raises(ValueError, match="Cannot render MJML with BytesIO/bytes"): mjml_tag._to_mjml() - # But passing the tag directly to mjml_to_intermediate_email should work - result = mjml_to_intermediate_email(mjml_tag) - assert isinstance(result, IntermediateEmail) + # But passing the tag directly to mjml_to_email should work + result = mjml_to_email(mjml_tag) + assert isinstance(result, Email) assert len(result.inline_attachments) == 1 -def test_quarto_json_to_intermediate_email_basic(tmp_path): +def test_quarto_json_to_email_basic(tmp_path): json_data = { "rsc_email_body_html": "

Quarto email

", "rsc_email_subject": "Quarto Test", @@ -233,7 +233,7 @@ def test_quarto_json_to_intermediate_email_basic(tmp_path): with open(json_file, "w") as f: json.dump(json_data, f) - result = quarto_json_to_intermediate_email(str(json_file)) + result = quarto_json_to_email(str(json_file)) assert result.subject == "Quarto Test" assert "

Quarto email

" in result.html @@ -244,7 +244,7 @@ def test_quarto_json_to_intermediate_email_basic(tmp_path): assert result.rsc_email_supress_scheduled is False -def test_quarto_json_to_intermediate_email_minimal(tmp_path): +def test_quarto_json_to_email_minimal(tmp_path): json_data = { "rsc_email_body_html": "Minimal", "rsc_email_subject": "Minimal Subject", @@ -254,7 +254,7 @@ def test_quarto_json_to_intermediate_email_minimal(tmp_path): with open(json_file, "w") as f: json.dump(json_data, f) - result = quarto_json_to_intermediate_email(str(json_file)) + result = quarto_json_to_email(str(json_file)) assert result.subject == "Minimal Subject" assert result.html == "Minimal" @@ -265,7 +265,7 @@ def test_quarto_json_to_intermediate_email_minimal(tmp_path): assert result.rsc_email_supress_scheduled is False -def test_quarto_json_to_intermediate_email_empty_lists(tmp_path): +def test_quarto_json_to_email_empty_lists(tmp_path): """Test handling empty lists for attachments and images.""" json_data = { "rsc_email_body_html": "Test", @@ -279,7 +279,7 @@ def test_quarto_json_to_intermediate_email_empty_lists(tmp_path): with open(json_file, "w") as f: json.dump(json_data, f) - result = quarto_json_to_intermediate_email(str(json_file)) + result = quarto_json_to_email(str(json_file)) assert result.external_attachments == [] assert result.inline_attachments == {} diff --git a/nbmail/tests/test_structs.py b/nbmail/tests/test_structs.py index b60db3e..60d9847 100644 --- a/nbmail/tests/test_structs.py +++ b/nbmail/tests/test_structs.py @@ -1,11 +1,11 @@ import re import pytest -from nbmail.structs import IntermediateEmail +from nbmail.structs import Email def test_creation_with_text_and_attachments(): - email = IntermediateEmail( + email = Email( html="

Hi

", subject="With Text and Attachments", text="Plain text version", @@ -21,7 +21,7 @@ def test_creation_with_text_and_attachments(): def test_creation_without_text_and_attachments(): - email = IntermediateEmail( + email = Email( html="

Hi

", subject="No Text or Attachments", ) @@ -34,7 +34,7 @@ def test_creation_without_text_and_attachments(): def test_subject_inserts_after_body(tmp_path): html = "

Hello!

" - email = IntermediateEmail( + email = Email( html=html, subject="Test Subject", rsc_email_supress_report_attachment=False, @@ -55,7 +55,7 @@ def test_subject_inserts_after_body(tmp_path): def test_subject_prepends_if_no_body(tmp_path): html = "

Hello!

" - email = IntermediateEmail( + email = Email( html=html, subject="NoBody", ) @@ -68,7 +68,7 @@ def test_subject_prepends_if_no_body(tmp_path): def test_raises_on_external_attachments(tmp_path): html = "

Test

" - email = IntermediateEmail( + email = Email( html=html, subject="Test", external_attachments=["file.txt"], @@ -88,7 +88,7 @@ def test_raises_on_external_attachments(tmp_path): ) def test_not_implemented_methods(method_name): """Test that unimplemented methods raise NotImplementedError.""" - email = IntermediateEmail( + email = Email( html="

Hi

", subject="Test", ) @@ -99,7 +99,7 @@ def test_not_implemented_methods(method_name): def test_preview_email_simple_html(tmp_path, snapshot): html = "

Hello World!

" - email = IntermediateEmail( + email = Email( html=html, subject="Simple Test Email", ) @@ -120,7 +120,7 @@ def test_preview_email_with_inline_attachments(tmp_path, snapshot): Banner """ - email = IntermediateEmail( + email = Email( html=html, subject="Email with Inline Images", inline_attachments={ @@ -163,7 +163,7 @@ def test_preview_email_complex_html(tmp_path, snapshot): """ - email = IntermediateEmail( + email = Email( html=html, subject="Complex Email Structure", inline_attachments={ From 17760633ed7fb248b276a3be9ce6986564087dbd Mon Sep 17 00:00:00 2001 From: Jules <54960783+juleswg23@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:05:45 -0500 Subject: [PATCH 3/4] rename intermediate email to email --- nbmail/ingress.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nbmail/ingress.py b/nbmail/ingress.py index 58b43aa..c2010bb 100644 --- a/nbmail/ingress.py +++ b/nbmail/ingress.py @@ -27,7 +27,7 @@ def redmail_to_email(msg: EmailMessage) -> Email: msg The Redmail-generated EmailMessage object - Converts the input EmailMessage to the intermediate email structure + Converts the input EmailMessage to the email structure """ return _email_message_to_email(msg) From 42525e69df7b4658c52ad9e5de7103b14691ebc0 Mon Sep 17 00:00:00 2001 From: Jules <54960783+juleswg23@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:46:58 -0500 Subject: [PATCH 4/4] refactor _wrap_in_mjml_tag to support quarto interactive rendering --- nbmail/ingress.py | 4 ++- nbmail/mjml/_core.py | 69 +++++++++++++++++++++++++++----------------- 2 files changed, 45 insertions(+), 28 deletions(-) diff --git a/nbmail/ingress.py b/nbmail/ingress.py index c2010bb..005686e 100644 --- a/nbmail/ingress.py +++ b/nbmail/ingress.py @@ -63,7 +63,9 @@ def mjml_to_email( """ # Handle MJMLTag objects by preprocessing images if isinstance(mjml_content, MJMLTag): - processed_mjml, inline_attachments = _process_mjml_images(mjml_content) + # Wrap in proper MJML structure if needed + wrapped_mjml = mjml_content._wrap_in_mjml_tag(emit_warning=True) + processed_mjml, inline_attachments = _process_mjml_images(wrapped_mjml) mjml_markup = processed_mjml._to_mjml() else: # String-based MJML, no preprocessing needed diff --git a/nbmail/mjml/_core.py b/nbmail/mjml/_core.py index c77a25d..9331639 100644 --- a/nbmail/mjml/_core.py +++ b/nbmail/mjml/_core.py @@ -193,6 +193,46 @@ def __repr__(self) -> str: ) return f"" + def _wrap_in_mjml_tag(self, emit_warning: bool = True) -> "MJMLTag": + """ + Wrap this tag in proper MJML structure if needed. + + If this is already a complete MJML document ( tag), return it as-is. + If this is an tag, wrap it in an tag. + Otherwise, wrap it in .... + + Parameters + ---------- + emit_warning + Whether to emit a warning when wrapping is performed + + Returns + ------- + MJMLTag + A complete MJML document (with root tag) + """ + if self.tagName == "mjml": + # Already a complete MJML document + return self + elif self.tagName == "mj-body": + # Wrap only in mjml tag + if emit_warning: + warnings.warn( + "Automatically wrapping in .... " + "For full control, create a complete MJML document with the mjml() tag.", + UserWarning, + ) + return MJMLTag("mjml", self) + else: + # Wrap in mjml and mj-body + if emit_warning: + warnings.warn( + "Automatically wrapping in .... " + "For full control, create a complete MJML document with the mjml() tag.", + UserWarning, + ) + return MJMLTag("mjml", MJMLTag("mj-body", self)) + # warning explain that they are not to pass this to email def to_html(self, **mjml2html_kwargs) -> str: """ @@ -214,31 +254,6 @@ def to_html(self, **mjml2html_kwargs) -> str: str Result from `mjml-python.mjml2html()` containing html content """ - if self.tagName == "mjml": - # Already a complete MJML document - mjml_markup = self._to_mjml() - elif self.tagName == "mj-body": - # Wrap only in mjml tag - warnings.warn( - "to_html() called on tag. " - "Automatically wrapping in .... " - "For full control, create a complete MJML document with the mjml() tag.", - UserWarning, - stacklevel=2, - ) - wrapped = MJMLTag("mjml", self) - mjml_markup = wrapped._to_mjml() - else: - # Warn and wrap in mjml/mj-body - warnings.warn( - f"to_html() called on <{self.tagName}> tag. " - "Automatically wrapping in .... " - "For full control, create a complete MJML document with the mjml() tag.", - UserWarning, - stacklevel=2, - ) - # Wrap in mjml and mj-body - wrapped = MJMLTag("mjml", MJMLTag("mj-body", self)) - mjml_markup = wrapped._to_mjml() - + wrapped = self._wrap_in_mjml_tag(emit_warning=True) + mjml_markup = wrapped._to_mjml() return mjml2html(mjml_markup, **mjml2html_kwargs)