Docs: simplify editing ESP feature matrix

Move the big ESP feature matrix table
into a CSV file for easier maintenance.

Remove the doc8 line-length exception
the old table needed.

Docutils csv-table directive doesn't
support colspan on the subheadings
like the old table did. Add some JS
that replicates the old behavior.
(The new table is still readable even
with JS disabled.)
This commit is contained in:
Mike Edmunds
2024-02-19 14:39:53 -08:00
parent 4f305131ee
commit 53546ffc19
5 changed files with 72 additions and 45 deletions

40
docs/_static/table-formatting.js vendored Normal file
View File

@@ -0,0 +1,40 @@
/**
* Return the first sibling of el that matches CSS selector, or null if no matches.
* @param {HTMLElement} el
* @param {string} selector
* @returns {HTMLElement|null}
*/
function nextSiblingMatching(el, selector) {
while (el && el.nextElementSibling) {
el = el.nextElementSibling;
if (el.matches(selector)) {
return el;
}
}
return null;
}
/**
* Convert runs of empty <td> elements to a colspan on the first <td>.
*/
function collapseEmptyTableCells() {
document.querySelectorAll(".rst-content tr:has(td:empty)").forEach((tr) => {
for (
let spanStart = tr.querySelector("td");
spanStart;
spanStart = nextSiblingMatching(spanStart, "td")
) {
let emptyCell;
while ((emptyCell = nextSiblingMatching(spanStart, "td:empty"))) {
emptyCell.remove();
spanStart.colSpan++;
}
}
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", collapseEmptyTableCells);
} else {
collapseEmptyTableCells();
}

View File

@@ -279,6 +279,7 @@ def setup(app):
anymail_config_js = (DOCS_PATH / "_static/anymail-config.js").read_text()
app.add_js_file(None, body=anymail_config_js)
app.add_js_file("version-alert.js", **{"async": "async"})
app.add_js_file("table-formatting.js", **{"async": "async"})
app.add_js_file("https://unpkg.com/rate-the-docs", **{"async": "async"})
# Django-specific roles, from

View File

@@ -0,0 +1,19 @@
Email Service Provider,:ref:`amazon-ses-backend`,:ref:`brevo-backend`,:ref:`mailersend-backend`,:ref:`mailgun-backend`,:ref:`mailjet-backend`,:ref:`mandrill-backend`,:ref:`postal-backend`,:ref:`postmark-backend`,:ref:`resend-backend`,:ref:`sendgrid-backend`,:ref:`sparkpost-backend`
.. rubric:: :ref:`Anymail send options <anymail-send-options>`,,,,,,,,,,,
:attr:`~AnymailMessage.envelope_sender`,Yes,No,No,Domain only,Yes,Domain only,Yes,No,No,No,Yes
:attr:`~AnymailMessage.metadata`,Yes,Yes,No,Yes,Yes,Yes,No,Yes,Yes,Yes,Yes
:attr:`~AnymailMessage.merge_metadata`,No,No,No,Yes,Yes,Yes,No,Yes,No,Yes,Yes
:attr:`~AnymailMessage.send_at`,No,Yes,Yes,Yes,No,Yes,No,No,No,Yes,Yes
:attr:`~AnymailMessage.tags`,Yes,Yes,Yes,Yes,Max 1 tag,Yes,Max 1 tag,Max 1 tag,Yes,Yes,Max 1 tag
:attr:`~AnymailMessage.track_clicks`,No,No,Yes,Yes,Yes,Yes,No,Yes,No,Yes,Yes
:attr:`~AnymailMessage.track_opens`,No,No,Yes,Yes,Yes,Yes,No,Yes,No,Yes,Yes
:ref:`amp-email`,Yes,No,No,Yes,No,No,No,No,No,Yes,Yes
.. rubric:: :ref:`templates-and-merge`,,,,,,,,,,,
:attr:`~AnymailMessage.template_id`,Yes,Yes,Yes,Yes,Yes,Yes,No,Yes,No,Yes,Yes
:attr:`~AnymailMessage.merge_data`,Yes,No,Yes,Yes,Yes,Yes,No,Yes,No,Yes,Yes
:attr:`~AnymailMessage.merge_global_data`,Yes,Yes,(emulated),(emulated),Yes,Yes,No,Yes,No,Yes,Yes
.. rubric:: :ref:`Status <esp-send-status>` and :ref:`event tracking <event-tracking>`,,,,,,,,,,,
:attr:`~AnymailMessage.anymail_status`,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes
:class:`~anymail.signals.AnymailTrackingEvent` from webhooks,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes
.. rubric:: :ref:`Inbound handling <inbound>`,,,,,,,,,,,
:class:`~anymail.signals.AnymailInboundEvent` from webhooks,Yes,Yes,Yes,Yes,Yes,Yes,Yes,Yes,No,Yes,Yes
1 Email Service Provider :ref:`amazon-ses-backend` :ref:`brevo-backend` :ref:`mailersend-backend` :ref:`mailgun-backend` :ref:`mailjet-backend` :ref:`mandrill-backend` :ref:`postal-backend` :ref:`postmark-backend` :ref:`resend-backend` :ref:`sendgrid-backend` :ref:`sparkpost-backend`
2 .. rubric:: :ref:`Anymail send options <anymail-send-options>`
3 :attr:`~AnymailMessage.envelope_sender` Yes No No Domain only Yes Domain only Yes No No No Yes
4 :attr:`~AnymailMessage.metadata` Yes Yes No Yes Yes Yes No Yes Yes Yes Yes
5 :attr:`~AnymailMessage.merge_metadata` No No No Yes Yes Yes No Yes No Yes Yes
6 :attr:`~AnymailMessage.send_at` No Yes Yes Yes No Yes No No No Yes Yes
7 :attr:`~AnymailMessage.tags` Yes Yes Yes Yes Max 1 tag Yes Max 1 tag Max 1 tag Yes Yes Max 1 tag
8 :attr:`~AnymailMessage.track_clicks` No No Yes Yes Yes Yes No Yes No Yes Yes
9 :attr:`~AnymailMessage.track_opens` No No Yes Yes Yes Yes No Yes No Yes Yes
10 :ref:`amp-email` Yes No No Yes No No No No No Yes Yes
11 .. rubric:: :ref:`templates-and-merge`
12 :attr:`~AnymailMessage.template_id` Yes Yes Yes Yes Yes Yes No Yes No Yes Yes
13 :attr:`~AnymailMessage.merge_data` Yes No Yes Yes Yes Yes No Yes No Yes Yes
14 :attr:`~AnymailMessage.merge_global_data` Yes Yes (emulated) (emulated) Yes Yes No Yes No Yes Yes
15 .. rubric:: :ref:`Status <esp-send-status>` and :ref:`event tracking <event-tracking>`
16 :attr:`~AnymailMessage.anymail_status` Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
17 :class:`~anymail.signals.AnymailTrackingEvent` from webhooks Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
18 .. rubric:: :ref:`Inbound handling <inbound>`
19 :class:`~anymail.signals.AnymailInboundEvent` from webhooks Yes Yes Yes Yes Yes Yes Yes Yes No Yes Yes

View File

@@ -33,56 +33,25 @@ The table below summarizes the Anymail features supported for each ESP.
.. currentmodule:: anymail.message
.. rst-class:: sticky-left
============================================ ============ ======= ============ =========== ========== =========== ========== ========== ======== ========== ===========
Email Service Provider |Amazon SES| |Brevo| |MailerSend| |Mailgun| |Mailjet| |Mandrill| |Postal| |Postmark| |Resend| |SendGrid| |SparkPost|
============================================ ============ ======= ============ =========== ========== =========== ========== ========== ======== ========== ===========
.. rubric:: :ref:`Anymail send options <anymail-send-options>`
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.envelope_sender` Yes No No Domain only Yes Domain only Yes No No No Yes
:attr:`~AnymailMessage.metadata` Yes Yes No Yes Yes Yes No Yes Yes Yes Yes
:attr:`~AnymailMessage.merge_metadata` No No No Yes Yes Yes No Yes No Yes Yes
:attr:`~AnymailMessage.send_at` No Yes Yes Yes No Yes No No No Yes Yes
:attr:`~AnymailMessage.tags` Yes Yes Yes Yes Max 1 tag Yes Max 1 tag Max 1 tag Yes Yes Max 1 tag
:attr:`~AnymailMessage.track_clicks` No No Yes Yes Yes Yes No Yes No Yes Yes
:attr:`~AnymailMessage.track_opens` No No Yes Yes Yes Yes No Yes No Yes Yes
:ref:`amp-email` Yes No No Yes No No No No No Yes Yes
.. rubric:: :ref:`templates-and-merge`
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.template_id` Yes Yes Yes Yes Yes Yes No Yes No Yes Yes
:attr:`~AnymailMessage.merge_data` Yes No Yes Yes Yes Yes No Yes No Yes Yes
:attr:`~AnymailMessage.merge_global_data` Yes Yes (emulated) (emulated) Yes Yes No Yes No Yes Yes
.. rubric:: :ref:`Status <esp-send-status>` and :ref:`event tracking <event-tracking>`
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
:attr:`~AnymailMessage.anymail_status` Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
|AnymailTrackingEvent| from webhooks Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
.. rubric:: :ref:`Inbound handling <inbound>`
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|AnymailInboundEvent| from webhooks Yes Yes Yes Yes Yes Yes Yes Yes No Yes Yes
============================================ ============ ======= ============ =========== ========== =========== ========== ========== ======== ========== ===========
.. It's much easier to edit esp-feature-matrix.csv with a CSV-aware editor, such as:
.. PyCharm (Pro has native CSV support; use a CSV editor plugin with Community)
.. VSCode with a CSV editor extension
.. Excel (watch out for charset issues), Apple Numbers, or Google Sheets
.. Every row must have the same number of columns. If you add a column, you must
.. also add a comma to each sub-heading row. (A CSV editor should handle this for you.)
.. Please keep columns sorted alphabetically by ESP name.
.. csv-table::
:file: esp-feature-matrix.csv
:header-rows: 1
:widths: auto
:class: sticky-left
Trying to choose an ESP? Please **don't** start with this table. It's far more
important to consider things like an ESP's deliverability stats, latency, uptime,
and support for developers. The *number* of extra features an ESP offers is almost
meaningless. (And even specific features don't matter if you don't plan to use them.)
.. |Amazon SES| replace:: :ref:`amazon-ses-backend`
.. |Brevo| replace:: :ref:`brevo-backend`
.. |MailerSend| replace:: :ref:`mailersend-backend`
.. |Mailgun| replace:: :ref:`mailgun-backend`
.. |Mailjet| replace:: :ref:`mailjet-backend`
.. |Mandrill| replace:: :ref:`mandrill-backend`
.. |Postal| replace:: :ref:`postal-backend`
.. |Postmark| replace:: :ref:`postmark-backend`
.. |Resend| replace:: :ref:`resend-backend`
.. |SendGrid| replace:: :ref:`sendgrid-backend`
.. |SparkPost| replace:: :ref:`sparkpost-backend`
.. |AnymailTrackingEvent| replace:: :class:`~anymail.signals.AnymailTrackingEvent`
.. |AnymailInboundEvent| replace:: :class:`~anymail.signals.AnymailInboundEvent`
Other ESPs
----------