diff --git a/anymail/backends/unisender_go.py b/anymail/backends/unisender_go.py index 83629fd9..4ea3219d 100644 --- a/anymail/backends/unisender_go.py +++ b/anymail/backends/unisender_go.py @@ -11,7 +11,7 @@ from anymail.backends.base_requests import AnymailRequestsBackend, RequestsPayload from anymail.exceptions import AnymailConfigurationError from anymail.message import AnymailRecipientStatus -from anymail.utils import Attachment, EmailAddress, get_anymail_setting +from anymail.utils import Attachment, EmailAddress, get_anymail_setting, update_deep class EmailBackend(AnymailRequestsBackend): @@ -42,7 +42,7 @@ def __init__(self, **kwargs: typing.Any): def build_message_payload( self, message: EmailMessage, defaults: dict ) -> UnisenderGoPayload: - return UnisenderGoPayload(message, defaults, self) + return UnisenderGoPayload(message=message, defaults=defaults, backend=self) def parse_recipient_status( self, response: Response, payload: UnisenderGoPayload, message: EmailMessage @@ -165,106 +165,12 @@ def __init__( def get_api_endpoint(self) -> str: return "email/send.json" - def set_skip_unsubscribe(self, extra: dict) -> None: - """ - By default, Unisender Go adds unsubscribe link. - - It's needed due to guarantee not abusing users with spam. - Before to use this setting, you have to request tech support. - - Expects skip_unsubscribe to be True or False, then transfers it to 0 or 1. - Anyway, works if skip_unsubscribe converts to True or False (for flexibility). - """ - if "skip_unsubscribe" in extra and extra["skip_unsubscribe"]: - self.data["skip_unsubscribe"] = 1 - - def set_global_language(self, extra): - """ - Language for link language and unsubscribe page. - Options: 'be', 'de', 'en', 'es', 'fr', 'it', 'pl', 'pt', 'ru', 'ua', 'kz'. - """ - if "global_language" in extra and extra["global_language"]: - self.data["global_language"] = extra["global_language"] - - def set_amp(self, extra): - """AMP-part of email""" - if "amp" in extra and extra["amp"]: - self.data["amp"] = extra["amp"] - - def set_bypass_settings(self, extra): - """ - Set extra settings with bypass prefix. - - bypass_global: optional 0/1 (0 by default) - If 1: To ignore list of global unavailability. - Can be forbidden for some system records. - - bypass_unavailable: optional 0/1 (0 by default) - If 1: To ignore current project unavailable addresses. - Works only with bypass_global = 1. - - bypass_unsubscribed: optional 0/1 (0 by default) - If 1: To ignore list of unsubscribed people. - Works only with bypass_global=1 and requires tech support's approve. - - bypass_complained: optional 0/1 (0 by default) - If 1: To ignore complainers on project. - Works only with bypass_global=1 and requires tech support's approve. - """ - bypass_fields = ( - "bypass_global", - "bypass_unavailable", - "bypass_unsubscribed", - "bypass_complained", - ) - for field in bypass_fields: - if field in extra: - self.data[field] = extra[field] - - def set_template_engine(self, extra): - """ - Templating choosing parameter. Can be either 'simple' or 'velocity' or 'none'. - - 'simple' by default. - 'none' available only for emails with - ‘track_links’ and ‘track_read’ equal 0 and with turned off unsubscribe block. - - "Simple" templating is for simple substitutions. - "Velocity" templating allows loops, arrays, etc. - """ - if "template_engine" in extra and extra["template_engine"]: - self.data["template_engine"] = extra["template_engine"] - def set_esp_extra(self, extra: dict) -> None: """Set every esp extra parameter with its docstring""" - self.set_skip_unsubscribe(extra) - self.set_global_language(extra) - self.set_template_engine(extra) - self.set_amp(extra) - self.set_bypass_settings(extra) - - def set_global_settings_from_config(self): - """ - Here we set variables from global config. - - If there is no esp_extra in backend's kwargs, set_esp_extra won't be called. - So we have to set default values in init. - You can change them with backend's kwarg esp_extra. - """ - if get_anymail_setting( - "skip_unsubscribe", esp_name=self.esp_name, default=False - ): - self.data["skip_unsubscribe"] = 1 - - global_language = get_anymail_setting( - "global_language", esp_name=self.esp_name, default=None - ) - if global_language: - self.data["global_language"] = global_language + update_deep(self.data, extra) def init_payload(self) -> None: self.data = {"headers": CaseInsensitiveDict()} # becomes json - self.set_global_settings_from_config() def serialize_data(self) -> str: """Performs any necessary serialization on self.data, and returns the result.""" @@ -323,7 +229,7 @@ def set_subject(self, subject: str) -> None: self.data["subject"] = subject def set_reply_to(self, emails: list[EmailAddress]) -> None: - # Unisunder GO only supports a single address in the reply_to API param. + # Unisender GO only supports a single address in the reply_to API param. if len(emails) > 1: self.unsupported_feature("multiple reply_to addresses") if len(emails) > 0: diff --git a/docs/esps/unisender_go.rst b/docs/esps/unisender_go.rst index fa97dd93..ee69d476 100644 --- a/docs/esps/unisender_go.rst +++ b/docs/esps/unisender_go.rst @@ -35,10 +35,10 @@ Anymail will also look for ``UNISENDER_GO_API_KEY`` at the root of the settings file if neither ``ANYMAIL["UNISENDER_GO_API_KEY"]`` nor ``ANYMAIL_UNISENDER_GO_API_KEY`` is set. -.. setting:: ANYMAIL_UNISENDER_GO_API_URL - .. rubric:: UNISENDER_GO_API_URL +.. setting:: ANYMAIL_UNISENDER_GO_API_URL + `Unisender GO API endpoint`_ to use. It can depend on server location. .. code-block:: python @@ -52,6 +52,53 @@ You must specify the full, versioned API endpoint as shown above (not just the b .. _Unisender GO API Endpoint: https://godocs.unisender.ru/web-api-ref#web-api +**global_language option** + Language for link language and unsubscribe page. + Options: 'be', 'de', 'en', 'es', 'fr', 'it', 'pl', 'pt', 'ru', 'ua', 'kz'. + + .. code-block:: python + + ANYMAIL={ + "UNISENDER_GO_SEND_DEFAULTS": {"esp_extra": {"global_language": "en"}} + } + +.. rubric:: BYPASS OPTIONS + +Set extra settings with bypass prefix. + +**bypass_global**: optional 0/1 (0 by default) +If 1: To ignore list of global unavailability. Can be forbidden for some system records. + +**bypass_unavailable**: optional 0/1 (0 by default) +If 1: To ignore current project unavailable addresses. Works only with bypass_global = 1. + +**bypass_unsubscribed**: optional 0/1 (0 by default) +If 1: To ignore list of unsubscribed people. Works only with bypass_global=1 and requires tech support's approve. + +**bypass_complained**: optional 0/1 (0 by default) +If 1: To ignore complainers on project. Works only with bypass_global=1 and requires tech support's approve. + + .. code-block:: python + + # in settings + ANYMAIL={ + "UNISENDER_GO_SEND_DEFAULTS": { + "esp_extra": { + "bypass_global": 1, + "bypass_unavailable": 1, + "bypass_unsubscribed": 1, + "bypass_complained": 1, + } + } + } + # or in Email class call + esp_extra={ + "bypass_global": 1, + "bypass_unavailable": 1, + "bypass_unsubscribed": 1, + "bypass_complained": 1, + } + Limitations and quirks ---------------------- @@ -69,15 +116,9 @@ Limitations and quirks .. code-block:: python - ANYMAIL_UNISENDER_GO_SKIP_UNSUBSCRIBE = True - -**global_language option** - Language for link language and unsubscribe page. - Options: 'be', 'de', 'en', 'es', 'fr', 'it', 'pl', 'pt', 'ru', 'ua', 'kz'. - - .. code-block:: python - - ANYMAIL_UNISENDER_GO_GLOBAL_LANGUAGE = 'en' + ANYMAIL={ + "UNISENDER_GO_SEND_DEFAULTS": {"esp_extra": {"skip_unsubscribe": 1}} + } .. _unisender-templates: diff --git a/tests/test_unisender_go_payload.py b/tests/test_unisender_go_payload.py index 46e233bb..f66faf37 100644 --- a/tests/test_unisender_go_payload.py +++ b/tests/test_unisender_go_payload.py @@ -21,7 +21,6 @@ @tag("unisender_go") @override_settings(ANYMAIL_UNISENDER_GO_API_KEY=None, ANYMAIL_UNISENDER_GO_API_URL="") class TestUnisenderGoPayload(SimpleTestCase): - @override_settings(ANYMAIL_UNISENDER_GO_SKIP_UNSUBSCRIBE=False) def test_unisender_go_payload__full(self): substitutions = {TO_EMAIL: SUBSTITUTION_ONE, OTHER_TO_EMAIL: SUBSTITUTION_TWO} email = AnymailMessageMixin( @@ -34,7 +33,9 @@ def test_unisender_go_payload__full(self): ) backend = EmailBackend() - payload = UnisenderGoPayload(message=email, backend=backend, defaults={}) + payload = UnisenderGoPayload( + message=email, backend=backend, defaults=backend.send_defaults + ) expected_payload = { "from_email": FROM_EMAIL, "from_name": FROM_NAME, @@ -56,7 +57,6 @@ def test_unisender_go_payload__full(self): self.assertEqual(payload.data, expected_payload) - @override_settings(ANYMAIL_UNISENDER_GO_SKIP_UNSUBSCRIBE=False) def test_unisender_go_payload__parse_from__with_name(self): email = AnymailMessageMixin( subject=SUBJECT, @@ -66,7 +66,9 @@ def test_unisender_go_payload__parse_from__with_name(self): ) backend = EmailBackend() - payload = UnisenderGoPayload(message=email, backend=backend, defaults={}) + payload = UnisenderGoPayload( + message=email, backend=backend, defaults=backend.send_defaults + ) expected_payload = { "from_email": FROM_EMAIL, "from_name": FROM_NAME, @@ -78,9 +80,6 @@ def test_unisender_go_payload__parse_from__with_name(self): self.assertEqual(payload.data, expected_payload) - @override_settings( - ANYMAIL_UNISENDER_GO_SKIP_UNSUBSCRIBE=False, - ) def test_unisender_go_payload__parse_from__without_name(self): email = AnymailMessageMixin( subject=SUBJECT, @@ -90,7 +89,9 @@ def test_unisender_go_payload__parse_from__without_name(self): ) backend = EmailBackend() - payload = UnisenderGoPayload(message=email, backend=backend, defaults={}) + payload = UnisenderGoPayload( + message=email, backend=backend, defaults=backend.send_defaults + ) expected_payload = { "from_email": FROM_EMAIL, "from_name": "", @@ -103,7 +104,7 @@ def test_unisender_go_payload__parse_from__without_name(self): self.assertEqual(payload.data, expected_payload) @override_settings( - ANYMAIL_UNISENDER_GO_SKIP_UNSUBSCRIBE=True, + ANYMAIL={"UNISENDER_GO_SEND_DEFAULTS": {"esp_extra": {"skip_unsubscribe": 1}}}, ) def test_unisender_go_payload__parse_from__with_unsub__in_settings(self): email = AnymailMessageMixin( @@ -114,7 +115,9 @@ def test_unisender_go_payload__parse_from__with_unsub__in_settings(self): ) backend = EmailBackend() - payload = UnisenderGoPayload(message=email, backend=backend, defaults={}) + payload = UnisenderGoPayload( + message=email, backend=backend, defaults=backend.send_defaults + ) expected_payload = { "from_email": FROM_EMAIL, "from_name": FROM_NAME, @@ -127,7 +130,9 @@ def test_unisender_go_payload__parse_from__with_unsub__in_settings(self): self.assertEqual(payload.data, expected_payload) - @override_settings(ANYMAIL_UNISENDER_GO_SKIP_UNSUBSCRIBE=False) + @override_settings( + ANYMAIL={"UNISENDER_GO_SEND_DEFAULTS": {"esp_extra": {"skip_unsubscribe": 0}}}, + ) def test_unisender_go_payload__parse_from__with_unsub__in_args(self): email = AnymailMessageMixin( subject=SUBJECT, @@ -138,7 +143,9 @@ def test_unisender_go_payload__parse_from__with_unsub__in_args(self): ) backend = EmailBackend() - payload = UnisenderGoPayload(message=email, backend=backend, defaults={}) + payload = UnisenderGoPayload( + message=email, backend=backend, defaults=backend.send_defaults + ) expected_payload = { "from_email": FROM_EMAIL, "from_name": FROM_NAME, @@ -152,7 +159,9 @@ def test_unisender_go_payload__parse_from__with_unsub__in_args(self): self.assertEqual(payload.data, expected_payload) @override_settings( - ANYMAIL_UNISENDER_GO_GLOBAL_LANGUAGE="en", + ANYMAIL={ + "UNISENDER_GO_SEND_DEFAULTS": {"esp_extra": {"global_language": "en"}} + }, ) def test_unisender_go_payload__parse_from__global_language__in_settings(self): email = AnymailMessageMixin( @@ -163,7 +172,9 @@ def test_unisender_go_payload__parse_from__global_language__in_settings(self): ) backend = EmailBackend() - payload = UnisenderGoPayload(message=email, backend=backend, defaults={}) + payload = UnisenderGoPayload( + message=email, backend=backend, defaults=backend.send_defaults + ) expected_payload = { "from_email": FROM_EMAIL, "from_name": FROM_NAME, @@ -176,7 +187,11 @@ def test_unisender_go_payload__parse_from__global_language__in_settings(self): self.assertEqual(payload.data, expected_payload) - @override_settings(ANYMAIL_UNISENDER_GO_GLOBAL_LANGUAGE="fr") + @override_settings( + ANYMAIL={ + "UNISENDER_GO_SEND_DEFAULTS": {"esp_extra": {"global_language": "fr"}} + }, + ) def test_unisender_go_payload__parse_from__global_language__in_args(self): email = AnymailMessageMixin( subject=SUBJECT, @@ -187,7 +202,9 @@ def test_unisender_go_payload__parse_from__global_language__in_args(self): ) backend = EmailBackend() - payload = UnisenderGoPayload(message=email, backend=backend, defaults={}) + payload = UnisenderGoPayload( + message=email, backend=backend, defaults=backend.send_defaults + ) expected_payload = { "from_email": FROM_EMAIL, "from_name": FROM_NAME, @@ -215,7 +232,9 @@ def test_unisender_go_payload__parse_from__bypass_esp_extra(self): ) backend = EmailBackend() - payload = UnisenderGoPayload(message=email, backend=backend, defaults={}) + payload = UnisenderGoPayload( + message=email, backend=backend, defaults=backend.send_defaults + ) expected_payload = { "from_email": FROM_EMAIL, "from_name": FROM_NAME,