From 6656af81f0bb10bf5c21c16d1ddc0d09d93eea1e Mon Sep 17 00:00:00 2001 From: Mike Manger Date: Mon, 25 Nov 2024 12:23:06 +0000 Subject: [PATCH 1/8] Add SENDGRID_HOST_URL setting to fix #129 --- README.md | 9 +++++---- sendgrid_backend/mail.py | 17 ++++++++++++++--- test/test_post_to_sendgrid.py | 32 +++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 56d0ab7..d9467dd 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,12 @@ To use the backend, simply install the package (using pip), set the `EMAIL_BACKE 1. To toggle sandbox mode (when django is running in DEBUG mode), set `SENDGRID_SANDBOX_MODE_IN_DEBUG = True/False`. 1. To err on the side of caution, this defaults to True, so emails sent in DEBUG mode will not be delivered, unless this setting is explicitly set to False. -2. `SENDGRID_ECHO_TO_STDOUT` will echo to stdout or any other file-like +1. `SENDGRID_ECHO_TO_STDOUT` will echo to stdout or any other file-like object that is passed to the backend via the `stream` kwarg. -3. `SENDGRID_TRACK_EMAIL_OPENS` - defaults to true and tracks email open events via the Sendgrid service. These events are logged in the Statistics UI, Email Activity interface, and are reported by the Event Webhook. -4. `SENDGRID_TRACK_CLICKS_HTML` - defaults to true and, if enabled in your Sendgrid account, will tracks click events on links found in the HTML message sent. -5. `SENDGRID_TRACK_CLICKS_PLAIN` - defaults to true and, if enabled in your Sendgrid account, will tracks click events on links found in the plain text message sent. +1. `SENDGRID_TRACK_EMAIL_OPENS` - defaults to true and tracks email open events via the Sendgrid service. These events are logged in the Statistics UI, Email Activity interface, and are reported by the Event Webhook. +1. `SENDGRID_TRACK_CLICKS_HTML` - defaults to true and, if enabled in your Sendgrid account, will tracks click events on links found in the HTML message sent. +1. `SENDGRID_TRACK_CLICKS_PLAIN` - defaults to true and, if enabled in your Sendgrid account, will tracks click events on links found in the plain text message sent. +1. `SENDGRID_HOST_URL` - Allows changing the base API URI. Set to `api.eu.sendgrid.com` to use the EU region. ## Usage diff --git a/sendgrid_backend/mail.py b/sendgrid_backend/mail.py index 6e6afb7..00fa0cb 100644 --- a/sendgrid_backend/mail.py +++ b/sendgrid_backend/mail.py @@ -73,16 +73,24 @@ def __init__(self, *args, **kwargs): # or passed as an argument to the init function, which takes precedence # over the setting. + sg_args = {} if "api_key" in kwargs: - self.sg = SendGridAPIClient(api_key=kwargs["api_key"]) + sg_args["api_key"] = kwargs["api_key"] elif hasattr(settings, "SENDGRID_API_KEY") and settings.SENDGRID_API_KEY: - self.sg = SendGridAPIClient(api_key=settings.SENDGRID_API_KEY) + sg_args["api_key"] = settings.SENDGRID_API_KEY else: raise ImproperlyConfigured( "settings.py must contain a value for SENDGRID_API_KEY. " + "You may also pass a value to the api_key argument (optional)." ) + if "host" in kwargs: + sg_args["host"] = kwargs["host"] + elif hasattr(settings, "SENDGRID_HOST_URL") and settings.SENDGRID_HOST_URL: + sg_args["host"] = settings.SENDGRID_HOST_URL + + self.sg = SendGridAPIClient(**sg_args) + # Configure sandbox mode based on settings sandbox_mode_in_debug = get_django_setting( "SENDGRID_SANDBOX_MODE_IN_DEBUG", True @@ -210,7 +218,10 @@ def set_prop(attachment, prop_name, value): filename = "part-{0}{1}".format(uuid.uuid4().hex, ext) set_prop(sg_attch, "filename", filename) # todo: Read content if stream? - set_prop(sg_attch, "content", django_attch.get_payload().replace("\n", "")) + payload = django_attch.get_payload() + #if isinstance(payload, str): + payload = payload.replace("\n", "") + set_prop(sg_attch, "content", payload) # Content-type handling. Includes the 'method' param. content_type = django_attch.get_content_type() diff --git a/test/test_post_to_sendgrid.py b/test/test_post_to_sendgrid.py index a444a08..d8cb641 100644 --- a/test/test_post_to_sendgrid.py +++ b/test/test_post_to_sendgrid.py @@ -13,7 +13,7 @@ class TestPostToSendgrid(SimpleTestCase): ) def test_post(self): """ - Sends a POST to sendgrid's live API using a private API key that is stored + Sends a POST to SendGrid's live API using a private API key that is stored in github. """ @@ -35,3 +35,33 @@ def test_post(self): ) val = msg.send() self.assertEqual(val, 1) + + @pytest.mark.skipif( + not os.environ.get("SENDGRID_API_KEY"), + reason="requires SENDGRID_API_KEY env var", + ) + def test_eu_post(self): + """ + Sends a POST to SendGrid's live EU API using a private API key that is stored + in GitHub. + """ + + SENDGRID_API_KEY = os.environ.get("SENDGRID_API_KEY") + + # Set DEBUG=True so sandbox mode is enabled + settings = { + "DEBUG": True, + "SENDGRID_API_KEY": SENDGRID_API_KEY, + "SENDGRID_HOST_URL": "api.eu.sendgrid.com", + "EMAIL_BACKEND": "sendgrid_backend.SendgridBackend", + } + + with override_settings(**settings): + msg = EmailMessage( + subject="Hello, World!", + body="Hello, World!", + from_email="Sam Smith ", + to=["John Doe "], + ) + val = msg.send() + self.assertEqual(val, 1) From ccbca744e453cd12fc79b586caec3b728773c7d2 Mon Sep 17 00:00:00 2001 From: Mike Manger Date: Mon, 25 Nov 2024 12:29:49 +0000 Subject: [PATCH 2/8] Bump mypy and add type check to fix issue --- dev-requirements.txt | 2 +- sendgrid_backend/mail.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 56e4923..58789d9 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -5,7 +5,7 @@ importlib-metadata==3.6.0 isort==5.7.0 jedi==0.10.2 mock==2.0.0 -mypy==0.920 +mypy==1.8 pytest==6.2.5 pytest-cov==3.0.0 tox==3.8.5 diff --git a/sendgrid_backend/mail.py b/sendgrid_backend/mail.py index 00fa0cb..b3fae5e 100644 --- a/sendgrid_backend/mail.py +++ b/sendgrid_backend/mail.py @@ -219,8 +219,8 @@ def set_prop(attachment, prop_name, value): set_prop(sg_attch, "filename", filename) # todo: Read content if stream? payload = django_attch.get_payload() - #if isinstance(payload, str): - payload = payload.replace("\n", "") + if isinstance(payload, str): + payload = payload.replace("\n", "") set_prop(sg_attch, "content", payload) # Content-type handling. Includes the 'method' param. From 4f99b4081f6f77721e6ea634b4a05b4bd9a9161b Mon Sep 17 00:00:00 2001 From: Mike Manger Date: Mon, 25 Nov 2024 12:30:54 +0000 Subject: [PATCH 3/8] Remove unused import from test --- test/test_mail.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_mail.py b/test/test_mail.py index bb7862a..b7d0d7a 100644 --- a/test/test_mail.py +++ b/test/test_mail.py @@ -13,7 +13,6 @@ Header, MailSettings, Personalization, - SpamCheck, Substitution, TrackingSettings, ) From 6f054e5cfb2094adc8160af510f42ceaeeca9f5f Mon Sep 17 00:00:00 2001 From: Mike Manger Date: Mon, 25 Nov 2024 12:40:59 +0000 Subject: [PATCH 4/8] Set mypy to 1.4.1 --- dev-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index 58789d9..fedabba 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -5,7 +5,7 @@ importlib-metadata==3.6.0 isort==5.7.0 jedi==0.10.2 mock==2.0.0 -mypy==1.8 +mypy==1.4.1 pytest==6.2.5 pytest-cov==3.0.0 tox==3.8.5 From d8453b6faad08a65c1c3e94f513bf140faa33f77 Mon Sep 17 00:00:00 2001 From: Mike Manger Date: Mon, 25 Nov 2024 13:29:56 +0000 Subject: [PATCH 5/8] Add https:// to API url --- README.md | 2 +- test/test_post_to_sendgrid.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d9467dd..861b645 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ To use the backend, simply install the package (using pip), set the `EMAIL_BACKE 1. `SENDGRID_TRACK_EMAIL_OPENS` - defaults to true and tracks email open events via the Sendgrid service. These events are logged in the Statistics UI, Email Activity interface, and are reported by the Event Webhook. 1. `SENDGRID_TRACK_CLICKS_HTML` - defaults to true and, if enabled in your Sendgrid account, will tracks click events on links found in the HTML message sent. 1. `SENDGRID_TRACK_CLICKS_PLAIN` - defaults to true and, if enabled in your Sendgrid account, will tracks click events on links found in the plain text message sent. -1. `SENDGRID_HOST_URL` - Allows changing the base API URI. Set to `api.eu.sendgrid.com` to use the EU region. +1. `SENDGRID_HOST_URL` - Allows changing the base API URI. Set to `https://api.eu.sendgrid.com` to use the EU region. ## Usage diff --git a/test/test_post_to_sendgrid.py b/test/test_post_to_sendgrid.py index d8cb641..fd4394e 100644 --- a/test/test_post_to_sendgrid.py +++ b/test/test_post_to_sendgrid.py @@ -52,7 +52,7 @@ def test_eu_post(self): settings = { "DEBUG": True, "SENDGRID_API_KEY": SENDGRID_API_KEY, - "SENDGRID_HOST_URL": "api.eu.sendgrid.com", + "SENDGRID_HOST_URL": "https://api.eu.sendgrid.com", "EMAIL_BACKEND": "sendgrid_backend.SendgridBackend", } From 0ec25b3c99cecf85be5b135d12a60dcce564fda9 Mon Sep 17 00:00:00 2001 From: Mike Manger Date: Mon, 25 Nov 2024 13:45:31 +0000 Subject: [PATCH 6/8] Add seperate TESTING_SENDGRID_EU_API_KEY for testing EU sub accounts --- test/test_post_to_sendgrid.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/test_post_to_sendgrid.py b/test/test_post_to_sendgrid.py index fd4394e..64a37a7 100644 --- a/test/test_post_to_sendgrid.py +++ b/test/test_post_to_sendgrid.py @@ -36,9 +36,10 @@ def test_post(self): val = msg.send() self.assertEqual(val, 1) + # TESTING_SENDGRID_EU_API_KEY is only used for testing. @pytest.mark.skipif( - not os.environ.get("SENDGRID_API_KEY"), - reason="requires SENDGRID_API_KEY env var", + not os.environ.get("TESTING_SENDGRID_EU_API_KEY"), + reason="requires TESTING_SENDGRID_EU_API_KEY env var", ) def test_eu_post(self): """ @@ -46,7 +47,7 @@ def test_eu_post(self): in GitHub. """ - SENDGRID_API_KEY = os.environ.get("SENDGRID_API_KEY") + SENDGRID_API_KEY = os.environ.get("TESTING_SENDGRID_EU_API_KEY") # Set DEBUG=True so sandbox mode is enabled settings = { From fad156fa7dc2a20ec4804dfc1fa31a7a4b7143ae Mon Sep 17 00:00:00 2001 From: Mike Manger Date: Mon, 25 Nov 2024 15:24:42 +0000 Subject: [PATCH 7/8] Pass EU settings var to workflow --- .github/workflows/pipeline.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 8f6b67a..2420d8c 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -44,4 +44,5 @@ jobs: - name: Test with tox env: SENDGRID_API_KEY: ${{ secrets.SENDGRID_API_KEY }} + TESTING_SENDGRID_EU_API_KEY: ${{ secrets.TESTING_SENDGRID_EU_API_KEY }} run: tox From 88441ec1aecbc06ec8ce8f7d9538be5d2901ff77 Mon Sep 17 00:00:00 2001 From: Mike Manger Date: Tue, 26 Nov 2024 09:56:50 +0000 Subject: [PATCH 8/8] Update tox config to pass TESTING_SENDGRID_EU_API_KEY to envs --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 3760dc2..af5319e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ legacy_tox_ini = """ commands = pytest ./test --cov=sendgrid_backend - passenv = + pass_env = SENDGRID_API_KEY + TESTING_SENDGRID_EU_API_KEY """ \ No newline at end of file