Skip to content

Commit

Permalink
Unisender Go: Fix esp_extra parameters getting (use update_deep)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arondit committed Jan 24, 2024
1 parent 80f382f commit e707ec3
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 126 deletions.
102 changes: 4 additions & 98 deletions anymail/backends/unisender_go.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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:
Expand Down
63 changes: 52 additions & 11 deletions docs/esps/unisender_go.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
----------------------

Expand All @@ -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:

Expand Down
53 changes: 36 additions & 17 deletions tests/test_unisender_go_payload.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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": "",
Expand All @@ -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(
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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(
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit e707ec3

Please sign in to comment.