Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding return path option for amazon ses emails #381

Merged
8 changes: 8 additions & 0 deletions docs/source/actions/email-action.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ AWS Region.

Default: ``us-east-1``


SPIDERMON_AWS_RETURN_PATH
~~~~~~~~~~~~~~~~~~~~~~~~~

Reply-To email address.

Default: ``None`` (replies will go to sender email address)

SMTP action settings
--------------------

Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"pytest-cov",
"pytest-mock",
"jinja2",
"boto3",
"lxml",
"premailer",
"scrapinghub",
Expand Down
11 changes: 10 additions & 1 deletion spidermon/contrib/actions/email/ses.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@ class SendSESEmail(SendEmail):
aws_access_key = None
aws_secret_key = None
aws_region_name = "us-east-1"
aws_return_path = None

def __init__(
self,
aws_access_key=None,
aws_secret_key=None,
aws_region_name=None,
aws_return_path=None,
*args,
**kwargs
):
super().__init__(*args, **kwargs)
self.aws_access_key = aws_access_key or self.aws_access_key
self.aws_secret_key = aws_secret_key or self.aws_secret_key
self.aws_region_name = aws_region_name or self.aws_region_name
self.aws_return_path = aws_return_path or self.aws_return_path
if not self.fake and not self.aws_access_key:
raise NotConfigured(
"You must provide a value for SPIDERMON_AWS_ACCESS_KEY_ID setting."
Expand All @@ -43,6 +46,7 @@ def from_crawler_kwargs(cls, crawler):
"aws_access_key": aws_access_key_id,
"aws_secret_key": aws_secret_access_key,
"aws_region_name": crawler.settings.get("SPIDERMON_AWS_REGION_NAME"),
"aws_return_path": crawler.settings.get("SPIDERMON_AWS_RETURN_PATH"),
}
)
return kwargs
Expand All @@ -65,8 +69,13 @@ def send_message(self, message, **kwargs):
aws_access_key_id=self.aws_access_key,
aws_secret_access_key=self.aws_secret_key,
)

raw_message = {"Data": message.as_string()}
if self.aws_return_path:
raw_message["X-SES-RETURN-PATH-ARN"] = self.aws_return_path

client.send_raw_email(
Source=self.sender,
Destinations=self._get_recipients(),
RawMessage={"Data": message.as_string()},
RawMessage=raw_message,
)
50 changes: 50 additions & 0 deletions tests/contrib/actions/email/email/test_ses_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from unittest.mock import patch, MagicMock
from spidermon.contrib.actions.email.ses import SendSESEmail

import pytest
from scrapy.utils.test import get_crawler
from scrapy import Spider


@pytest.fixture
def test_settings():
return {
"SPIDERMON_AWS_REGION_NAME": "fake",
"SPIDERMON_AWS_ACCESS_KEY": "fake",
"SPIDERMON_AWS_SECRET_KEY": "fake",
"SPIDERMON_EMAIL_TO": "fake@test.com",
"SPIDERMON_EMAIL_SUBJECT": "fake",
"SPIDERMON_BODY_TEXT_TEMPLATE": "fake",
}


def run_mailer(test_settings):
mock_spider = MagicMock()
mock_spider.name = "test"

crawler = get_crawler(Spider, test_settings)
mailer = SendSESEmail.from_crawler(crawler)
mailer.send_message(MagicMock())


@patch("spidermon.contrib.actions.email.ses.boto3")
def test_ses_no_return_path(mock_boto3, test_settings):
run_mailer(test_settings)

mock_boto3.client().send_raw_email.assert_called()

kwargs = mock_boto3.client().send_raw_email.call_args[1]
message = kwargs.get("RawMessage")
assert message.get("X-SES-RETURN-PATH-ARN") is None


@patch("spidermon.contrib.actions.email.ses.boto3")
def test_ses_return_path(mock_boto3, test_settings):
test_settings["SPIDERMON_AWS_RETURN_PATH"] = "return@path.com"
run_mailer(test_settings)

mock_boto3.client().send_raw_email.assert_called()

kwargs = mock_boto3.client().send_raw_email.call_args[1]
message = kwargs.get("RawMessage")
assert message.get("X-SES-RETURN-PATH-ARN") == "return@path.com"