bringing the repo up to date with the code

git-svn-id: https://vault.zeeksgeeks.com/svn/django_aws_ses/trunk@6 ed966f06-d3d6-432b-bc91-693151a5c6b4
This commit is contained in:
Raymond Jessop 2023-11-07 19:32:25 +00:00
parent 54b5c97ce9
commit 823d6c1b2d
7 changed files with 316 additions and 119 deletions

View File

@ -6,7 +6,8 @@ from .models import (
AwsSesUserAddon,
ComplaintRecord,
SendRecord,
UnknownRecord
UnknownRecord,
BlackListedDomains,
)
from . import settings
@ -62,15 +63,22 @@ class ComplaintRecordAdmin(admin.ModelAdmin):
admin.site.register(ComplaintRecord, ComplaintRecordAdmin)
class SendRecordAdmin(admin.ModelAdmin):
model = ComplaintRecord
model = SendRecord
list_display = ('source', 'destination', 'subject', 'timestamp', 'status')
list_filter = ('source', 'destination', 'subject', 'timestamp', 'status')
admin.site.register(SendRecord, SendRecordAdmin)
class UnknownRecordAdmin(admin.ModelAdmin):
model = ComplaintRecord
model = UnknownRecord
list_display = ('event_type', 'aws_data')
list_filter = ('event_type', 'aws_data')
admin.site.register(UnknownRecord, UnknownRecordAdmin)
admin.site.register(UnknownRecord, UnknownRecordAdmin)
class BlackListedDomainsAdmin(admin.ModelAdmin):
model = BlackListedDomains
list_display = ('domain', 'timestamp')
list_filter = ('domain', 'timestamp')
admin.site.register(BlackListedDomains, BlackListedDomainsAdmin)

View File

@ -2,5 +2,6 @@ from django.apps import AppConfig
class DjangoAwsSesBackendConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'django_aws_ses'
verbose_name = 'Django AWS SES'

View File

@ -13,7 +13,8 @@ import sys
from . import settings
from . import signals
from . import utils
from .models import BounceRecord
from .models import BounceRecord
from saleor.core.utils import email_exclusion_filter
logger = settings.logger
@ -82,6 +83,8 @@ class SESBackend(BaseEmailBackend):
except Exception:
if not self.fail_silently:
raise
return True
def close(self):
"""Close any open HTTP connections to the API server.
@ -90,10 +93,13 @@ class SESBackend(BaseEmailBackend):
def send_messages(self, email_messages):
"""Sends one or more EmailMessage objects and returns the number of
email messages sent.
email messages sent and a list of filtered emails.
"""
logger.info("1 --- start of send_messages")
list_of_response = []
num_sent = 0
not_sent_list = []
sent_message = {"Sent":""}
calling_func = ''
try:
fcount = 0
@ -103,22 +109,31 @@ class SESBackend(BaseEmailBackend):
calling_func = sys._getframe(fcount).f_code.co_name
except Exception as e:
logger.info("fcount:%s, called from exception = %s" , (fcount, e))
logger.info("fcount:%s, called from exception = %s" % (fcount, e))
logger.info("called from %s" , (calling_func))
logger.info("called from %s current throttle:%s" % (calling_func, self._throttle))
logger.info("send_messages")
if not email_messages:
return
logger.info("no email messages returning")
list_of_response.append({'error':'no email messages returning'})
new_conn_created = self.open()
if new_conn_created:
logger.info("created a new connection")
if not self.connection:
# Failed silently
return
logger.info("no connection returning")
list_of_response.append({'error':'no connection returning'})
logger.info("DEBUGING EMAILS --- list_of_response:%s" % (list_of_response))
logger.info("DEBUGING EMAILS --- return %s" % (num_sent))
return num_sent
num_sent = 0
source = settings.AWS_SES_RETURN_PATH
logger.info("email_messages: %s" % email_messages)
@ -131,16 +146,43 @@ class SESBackend(BaseEmailBackend):
# If settings.AWS_SES_CONFIGURATION_SET is a callable, pass it the
# message object and dkim settings and expect it to return a string
# containing the SES Configuration Set name.
message.aws_ses_response = {'error':'not sent yet'}
logger.info("Sending signal(email_pre_send)")
signals.email_pre_send.send_robust(self.__class__, message=message)
logger.info("message to: %s, cc: %s, bcc: %s" % (message.to, message.cc, message.bcc))
signals.email_pre_send.send_robust(self.__class__, message=message)
# for log in dir(message):
# logger.info(log)
pre_filter_recipients = message.recipients()
logger.info("message.recipients() = %s" % message.recipients())
marketing = message.extra_headers.get("marketing","False")
message.to = email_exclusion_filter(message.to,marketing)
message.cc = email_exclusion_filter(message.cc,marketing)
message.bcc = email_exclusion_filter(message.bcc,marketing)
message.to = utils.filter_recipiants(message.recipients())
message.to = utils.filter_recipiants(message.to)
message.cc = utils.filter_recipiants(message.cc)
message.bcc = utils.filter_recipiants(message.bcc)
logger.info("message.recipients() after email_pre_send: %s" % message.recipients())
if not message.recipients():
logger.info("no recipients left after the filter")
return False
list_of_response.append({'error':'no recipients left after the filter'})
message.aws_ses_response = {'error':'no recipients left after the filter'}
sent_message = {"Not Sent":"No recipients left after filters"}
continue
#raise Exception('No emails left after filters!')
else:
for email in pre_filter_recipients:
if email not in message.recipients():
not_sent_list.append(email)
if (settings.AWS_SES_CONFIGURATION_SET
and 'X-SES-CONFIGURATION-SET' not in message.extra_headers):
@ -164,13 +206,16 @@ class SESBackend(BaseEmailBackend):
# Set the setting to 0 or None to disable throttling.
if self._throttle:
global recent_send_times
logger.info("inside if _throttle recent_send_times:%s" % recent_send_times)
now = datetime.now()
logger.info("inside if _throttle now:%s" % now)
# Get and cache the current SES max-per-second rate limit
# returned by the SES API.
logger.info("inside if _throttle calling get_rate_limit")
rate_limit = self.get_rate_limit()
logger.debug(u"send_messages.throttle rate_limit='{}'".format(rate_limit))
logger.info("send_messages.throttle rate_limit='{}'".format(rate_limit))
# Prune from recent_send_times anything more than a few seconds
# ago. Even though SES reports a maximum per-second, the way
@ -208,7 +253,7 @@ class SESBackend(BaseEmailBackend):
logger.info("Try to send raw email")
#logger.info('message.message().as_string() = %s' % message.message().as_string())
logger.info("source = %s" % source)
logger.info("message.from_email = %s" % self.dkim_key)
logger.info("message.from_email = %s" % message.from_email)
logger.info("message.recipients() = %s" % message.recipients())
logger.info("dkim_key = %s" % self.dkim_key)
@ -221,16 +266,21 @@ class SESBackend(BaseEmailBackend):
# todo attachments?
RawMessage={'Data': dkim_sign(message.message().as_string(),
dkim_key=self.dkim_key,
dkim_domain=self.dkim_domain,
dkim_domain=self.dkim_domain,
dkim_selector=self.dkim_selector,
dkim_headers=self.dkim_headers)}
)
list_of_response.append(response)
message.aws_ses_response = response
message.extra_headers['status'] = 200
message.extra_headers['message_id'] = response['MessageId']
message.extra_headers['request_id'] = response['ResponseMetadata']['RequestId']
num_sent += 1
if 'X-SES-CONFIGURATION-SET' in message.extra_headers:
logger.debug(
logger.info(
u"send_messages.sent from='{}' recipients='{}' message_id='{}' request_id='{}' "
u"ses-configuration-set='{}'".format(
message.from_email,
@ -240,7 +290,7 @@ class SESBackend(BaseEmailBackend):
message.extra_headers['X-SES-CONFIGURATION-SET']
))
else:
logger.debug(u"send_messages.sent from='{}' recipients='{}' message_id='{}' request_id='{}'".format(
logger.info(u"send_messages.sent from='{}' recipients='{}' message_id='{}' request_id='{}'".format(
message.from_email,
", ".join(message.recipients()),
message.extra_headers['message_id'],
@ -255,26 +305,41 @@ class SESBackend(BaseEmailBackend):
message.extra_headers[key] = getattr(err, key, None)
if not self.fail_silently:
raise
if not_sent_list:
sent_message.update({"Sent":"%s" % not_sent_list})
logger.info("new_conn_created: %s" % new_conn_created)
if new_conn_created:
logger.info("closing new connection after send")
self.close()
return num_sent
logger.info("DEBUGING EMAILS --- list_of_response:%s" % (list_of_response))
logger.info("DEBUGING EMAILS --- return %s, %s" % (num_sent, sent_message))
return num_sent, sent_message
def get_rate_limit(self):
logger.info("getting rate limit")
if self._access_key_id in cached_rate_limits:
logger.info("returning cached rate limit %s" % cached_rate_limits[self._access_key_id])
return cached_rate_limits[self._access_key_id]
logger.info("creating AWS connection")
new_conn_created = self.open()
if not self.connection:
logger.info("AWS connection creation failed")
raise Exception(
"No connection is available to check current SES rate limit.")
try:
quota_dict = self.connection.get_send_quota()
logger.info("AWS quota dict %s" % quota_dict)
max_per_second = quota_dict['MaxSendRate']
ret = float(max_per_second)
cached_rate_limits[self._access_key_id] = ret
return ret
finally:
if new_conn_created:
self.close()
self.close()

View File

@ -1,5 +1,6 @@
import hashlib
import logging
import traceback
from django.conf import settings
from django.db import models
@ -25,9 +26,15 @@ class AwsSesSettings(models.Model):
@receiver(post_save, sender=Site)
def update_awsses_settings(sender, instance, created, **kwargs):
if created:
AwsSesSettings.objects.create(Site=instance)
instance.AwsSesSettings.save()
try:
if created:
AwsSesSettings.objects.create(site=instance)
instance.awssessettings.save()
except Exception as e:
print("Exception saving site error:%s" % e)
track = traceback.format_exc()
print("Exception saving site track: %s" % (track))
class AwsSesUserAddon(models.Model):
user = models.OneToOneField(User, related_name='aws_ses', on_delete=models.CASCADE)
@ -87,9 +94,12 @@ class BounceRecord(models.Model):
status = models.CharField(max_length=255, blank=True, null=True,)
action = models.CharField(max_length=255, blank=True, null=True,)
feedback_id = models.TextField(max_length=255, blank=True, null=True,)
diagnostic_code = models.CharField(max_length=255, blank=True, null=True,)
diagnostic_code = models.CharField(max_length=2048, blank=True, null=True,)
cleared = models.BooleanField(default=False)
class Meta:
indexes = [models.Index(fields=["email"]),]
def __str__(self):
return "email: %s, type: %s, sub_type: %s, status: %s, date: %s" % (self.email, self.bounce_type, self.bounce_sub_type, self.status, self.timestamp)
@ -104,7 +114,6 @@ class ComplaintRecord(models.Model):
return "email: %s, sub_type: %s, feedback_type: %s, date: %s" % (self.email, self.bounce_sub_type, self.feedback_type, self.timestamp)
class SendRecord(models.Model):
SEND = 'Send'
DELIVERED = 'Delivery'
@ -121,6 +130,9 @@ class SendRecord(models.Model):
aws_process_time = models.IntegerField()
smtp_response = models.CharField(max_length=255, blank=True, null=True,)
status = models.CharField(max_length=255, blank=True, null=True,)
class Meta:
indexes = [models.Index(fields=["destination"]),]
def __str__(self):
return "source: %s, destination: %s, subject: %s, date: %s" % (self.source, self.destination, self.subject, self.timestamp)
@ -133,4 +145,10 @@ class UnknownRecord(models.Model):
def __str__(self):
return "eventType: %s, timestamp: %s" % (self.eventType, self.timestamp)
class BlackListedDomains(models.Model):
domain = models.CharField(max_length=255, unique=True)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return "%s, blocked: %s" % (self.domain, self.timestamp)

View File

@ -1,83 +1,106 @@
from django.conf import settings
from django.contrib.sites.models import Site
import logging
from .models import (
AwsSesSettings
)
__all__ = ('ACCESS_KEY', 'SECRET_KEY', 'AWS_SES_REGION_NAME',
'AWS_SES_REGION_ENDPOINT', 'AWS_SES_AUTO_THROTTLE',
'AWS_SES_RETURN_PATH', 'DKIM_DOMAIN', 'DKIM_PRIVATE_KEY',
'DKIM_SELECTOR', 'DKIM_HEADERS', 'TIME_ZONE', 'BASE_DIR',
'BOUNCE_LIMIT','SES_BACKEND_DEBUG','SES_BACKEND_DEBUG_LOGFILE_PATH',
'SES_BACKEND_DEBUG_LOGFILE_FORMATTER')
aws_ses_Settings = None
try:
aws_ses_Settings, c = AwsSesSettings.objects.get_or_create(site_id=settings.SITE_ID)
except Exception as e:
print("AwsSesSettings does not exist: error: %s" % e)
else:
__all__ = ('ACCESS_KEY', 'SECRET_KEY', 'AWS_SES_REGION_NAME',
'AWS_SES_REGION_ENDPOINT', 'AWS_SES_AUTO_THROTTLE',
'AWS_SES_RETURN_PATH', 'DKIM_DOMAIN', 'DKIM_PRIVATE_KEY',
'DKIM_SELECTOR', 'DKIM_HEADERS', 'TIME_ZONE', 'BASE_DIR',
'BOUNCE_LIMIT','SES_BACKEND_DEBUG','SES_BACKEND_DEBUG_LOGFILE_PATH',
'SES_BACKEND_DEBUG_LOGFILE_FORMATTER')
BASE_DIR = getattr(settings, 'BASE_DIR', None)
ACCESS_KEY = aws_ses_Settings.access_key if aws_ses_Settings else None
if ACCESS_KEY is None:
ACCESS_KEY = getattr(settings, 'AWS_SES_ACCESS_KEY_ID',getattr(settings, 'AWS_ACCESS_KEY_ID', None))
if not BASE_DIR:
raise RuntimeError('No BASE_DIR defined in project settings, django_aws_ses requires BASE_DIR to be defined and pointed at your root directory. i.e. BASE_DIR = os.path.dirname(os.path.abspath(__file__))')
SECRET_KEY = aws_ses_Settings.secret_key if aws_ses_Settings else None
if SECRET_KEY is None:
SECRET_KEY = getattr(settings, 'AWS_SES_SECRET_ACCESS_KEY',getattr(settings, 'AWS_SECRET_ACCESS_KEY', None))
DEFAULT_FROM_EMAIL = getattr(settings, 'DEFAULT_FROM_EMAIL', 'no_reply@%s' % aws_ses_Settings.site.domain)
AWS_SES_REGION_NAME = aws_ses_Settings.region_name if aws_ses_Settings else None
if AWS_SES_REGION_NAME is None:
AWS_SES_REGION_NAME = getattr(settings, 'AWS_SES_REGION_NAME',getattr(settings, 'AWS_DEFAULT_REGION', 'us-east-1'))
HOME_URL = getattr(settings, 'HOME_URL', '')
AWS_SES_REGION_ENDPOINT = aws_ses_Settings.region_endpoint if aws_ses_Settings else None
if AWS_SES_REGION_ENDPOINT is None:
AWS_SES_REGION_ENDPOINT = getattr(settings, 'AWS_SES_REGION_ENDPOINT','email.us-east-1.amazonaws.com')
UNSUBSCRIBE_TEMPLET = getattr(settings, 'UNSUBSCRIBE_TEMPLET', 'django_aws_ses/unsebscribe.html')
BASE_TEMPLET = getattr(settings, 'UNSUBSCRIBE_TEMPLET', 'django_aws_ses/base.html')
BASE_DIR = getattr(settings, 'BASE_DIR', None)
DEFAULT_FROM_EMAIL = ""
try:
site = Site.objects.get_current()
DEFAULT_FROM_EMAIL = getattr(settings, 'DEFAULT_FROM_EMAIL', 'no_reply@%s' % site.domain)
except Exception as e:
print("Site Doesn't Exist, please configure Django sites")
print("Error is: %s" % e)
ACCESS_KEY = aws_ses_Settings.access_key or getattr(settings, 'AWS_SES_ACCESS_KEY_ID',getattr(settings, 'AWS_ACCESS_KEY_ID', None))
HOME_URL = getattr(settings, 'HOME_URL', '')
if not BASE_DIR:
raise RuntimeError('No BASE_DIR defined in project settings, django_aws_ses requires BASE_DIR to be defined and pointed at your root directory. i.e. BASE_DIR = os.path.dirname(os.path.abspath(__file__))')
UNSUBSCRIBE_TEMPLET = getattr(settings, 'UNSUBSCRIBE_TEMPLET', 'django_aws_ses/unsebscribe.html')
BASE_TEMPLET = getattr(settings, 'UNSUBSCRIBE_TEMPLET', 'django_aws_ses/base.html')
AWS_SES_REGION_ENDPOINT_URL = getattr(settings, 'AWS_SES_REGION_ENDPOINT_URL','https://' + AWS_SES_REGION_ENDPOINT)
SECRET_KEY = aws_ses_Settings.secret_key or getattr(settings, 'AWS_SES_SECRET_ACCESS_KEY',getattr(settings, 'AWS_SECRET_ACCESS_KEY', None))
AWS_SES_AUTO_THROTTLE = getattr(settings, 'AWS_SES_AUTO_THROTTLE', 0.5)
AWS_SES_RETURN_PATH = getattr(settings, 'AWS_SES_RETURN_PATH', None)
# if AWS_SES_RETURN_PATH is None:
# AWS_SES_RETURN_PATH = "CF Doors <cdfbounced@zeeksgeeks.com>"
AWS_SES_REGION_NAME = aws_ses_Settings.region_name or getattr(settings, 'AWS_SES_REGION_NAME',getattr(settings, 'AWS_DEFAULT_REGION', 'us-east-1'))
AWS_SES_CONFIGURATION_SET = getattr(settings, 'AWS_SES_CONFIGURATION_SET', None)
DKIM_DOMAIN = getattr(settings, "DKIM_DOMAIN", None)
DKIM_PRIVATE_KEY = getattr(settings, 'DKIM_PRIVATE_KEY', None)
DKIM_SELECTOR = getattr(settings, 'DKIM_SELECTOR', 'ses')
DKIM_HEADERS = getattr(settings, 'DKIM_HEADERS', ('From', 'To', 'Cc', 'Subject'))
TIME_ZONE = settings.TIME_ZONE
VERIFY_BOUNCE_SIGNATURES = getattr(settings, 'AWS_SES_VERIFY_BOUNCE_SIGNATURES', True)
# Domains that are trusted when retrieving the certificate
# used to sign bounce messages.
BOUNCE_CERT_DOMAINS = getattr(settings, 'AWS_SNS_BOUNCE_CERT_TRUSTED_DOMAINS', (
'amazonaws.com',
'amazon.com',
))
SES_BOUNCE_LIMIT = getattr(settings,'BOUNCE_LIMT', 1)
AWS_SES_REGION_ENDPOINT = aws_ses_Settings.region_endpoint or getattr(settings, 'AWS_SES_REGION_ENDPOINT','email.us-east-1.amazonaws.com')
SES_BACKEND_DEBUG = getattr(settings,'SES_BACKEND_DEBUG', False)
AWS_SES_REGION_ENDPOINT_URL = getattr(settings, 'AWS_SES_REGION_ENDPOINT_URL','https://' + AWS_SES_REGION_ENDPOINT)
AWS_SES_AUTO_THROTTLE = getattr(settings, 'AWS_SES_AUTO_THROTTLE', 0.5)
AWS_SES_RETURN_PATH = getattr(settings, 'AWS_SES_RETURN_PATH', None)
AWS_SES_CONFIGURATION_SET = getattr(settings, 'AWS_SES_CONFIGURATION_SET', None)
DKIM_DOMAIN = getattr(settings, "DKIM_DOMAIN", None)
DKIM_PRIVATE_KEY = getattr(settings, 'DKIM_PRIVATE_KEY', None)
DKIM_SELECTOR = getattr(settings, 'DKIM_SELECTOR', 'ses')
DKIM_HEADERS = getattr(settings, 'DKIM_HEADERS', ('From', 'To', 'Cc', 'Subject'))
TIME_ZONE = settings.TIME_ZONE
VERIFY_BOUNCE_SIGNATURES = getattr(settings, 'AWS_SES_VERIFY_BOUNCE_SIGNATURES', True)
# Domains that are trusted when retrieving the certificate
# used to sign bounce messages.
BOUNCE_CERT_DOMAINS = getattr(settings, 'AWS_SNS_BOUNCE_CERT_TRUSTED_DOMAINS', (
'amazonaws.com',
'amazon.com',
))
SES_BOUNCE_LIMIT = getattr(settings,'BOUNCE_LIMT', 1)
SES_BACKEND_DEBUG = getattr(settings,'SES_BACKEND_DEBUG', False)
SES_BACKEND_DEBUG_LOGFILE_PATH = getattr(settings,'SES_BACKEND_DEBUG_LOGFILE_PATH', '%s/aws_ses.log' % BASE_DIR)
SES_BACKEND_DEBUG_LOGFILE_FORMATTER = getattr(settings,'SES_BACKEND_DEBUG_LOGFILE_FORMATTER', '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('django_aws_ses')
# logger.setLevel(logging.WARNING)
if SES_BACKEND_DEBUG:
logger.setLevel(logging.INFO)
# create a file handler
if SES_BACKEND_DEBUG_LOGFILE_PATH:
handler = logging.FileHandler(SES_BACKEND_DEBUG_LOGFILE_PATH)
handler.setLevel(logging.INFO)
# create a logging format
formatter = logging.Formatter(SES_BACKEND_DEBUG_LOGFILE_FORMATTER)
handler.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(handler)
#logger.info('something we are logging')
SES_BACKEND_DEBUG_LOGFILE_PATH = getattr(settings,'SES_BACKEND_DEBUG_LOGFILE_PATH', '%s/aws_ses.log' % BASE_DIR)
SES_BACKEND_DEBUG_LOGFILE_FORMATTER = getattr(settings,'SES_BACKEND_DEBUG_LOGFILE_FORMATTER', '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger('django_aws_ses')
# logger.setLevel(logging.WARNING)
if SES_BACKEND_DEBUG:
logger.setLevel(logging.INFO)
# create a file handler
if SES_BACKEND_DEBUG_LOGFILE_PATH:
handler = logging.FileHandler(SES_BACKEND_DEBUG_LOGFILE_PATH)
handler.setLevel(logging.INFO)
# create a logging format
formatter = logging.Formatter(SES_BACKEND_DEBUG_LOGFILE_FORMATTER)
handler.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(handler)
#logger.info('something we are logging')

View File

@ -1,5 +1,9 @@
import base64
import logging
import time
import re
import dns.resolver
from telnetlib import Telnet
from builtins import str as text
from builtins import bytes
from io import StringIO
@ -19,7 +23,9 @@ from . import settings
from . import signals
from .models import (
BounceRecord,
ComplaintRecord
ComplaintRecord,
BlackListedDomains,
SendRecord,
)
logger = settings.logger
@ -211,30 +217,40 @@ def verify_bounce_message(msg):
@receiver(signals.email_pre_send)
def receiver_email_pre_send(sender, message=None, **kwargs):
logger.info("receiver_email_pre_send received signal")
#logger.info("receiver_email_pre_send received signal")
pass
def filter_recipiants(recipiant_list):
logger.info("Starting filter_recipiants: %s" % recipiant_list)
if type(recipiant_list) != type([]):
logger.info("putting emails into a list")
recipiant_list = [recipiant_list]
if len(recipiant_list) > 0:
recipiant_list = filter_recipiants_with_unsubscribe(recipiant_list)
recipiant_list = filter_recipiants_with_unsubscribe(recipiant_list)
if len(recipiant_list) > 0:
recipiant_list = filter_recipiants_with_complaint_records(recipiant_list)
if len(recipiant_list) > 0:
recipiant_list = filter_recipiants_with_bounce_records(recipiant_list)
if len(recipiant_list) > 0:
recipiant_list = filter_recipiants_with_validater_email_domain(recipiant_list)
logger.info("recipiant list after filter_recipiants: %s" % recipiant_list)
return recipiant_list
def filter_recipiants_with_unsubscribe(recipiant_list):
"""
filter message recipiants so we don't send emails to any email that have Unsubscribude
"""
logger.info("unsubscribe filter running")
#logger.info("unsubscribe filter running")
logger.info("message.recipients() befor blacklist_emails filter: %s" % recipiant_list)
#logger.info("message.recipients() befor blacklist_emails filter: %s" % recipiant_list)
blacklist_emails = list(set([record.email for record in User.objects.filter(aws_ses__unsubscribe=True)]))
if blacklist_emails:
return filter_recipiants_with_blacklist(recipiant_list, blacklist_emails)
else:
@ -244,9 +260,9 @@ def filter_recipiants_with_complaint_records(recipiant_list):
"""
filter message recipiants so we don't send emails to any email that have a ComplaintRecord
"""
logger.info("complaint_records filter running")
#logger.info("complaint_records filter running")
logger.info("message.recipients() befor blacklist_emails filter: %s" % recipiant_list)
#logger.info("message.recipients() befor blacklist_emails filter: %s" % recipiant_list)
blacklist_emails = list(set([record.email for record in ComplaintRecord.objects.filter(email__isnull=False)]))
if blacklist_emails:
@ -259,21 +275,87 @@ def filter_recipiants_with_bounce_records(recipiant_list):
filter message recipiants so we dont send emails to any email that has more BounceRecord
the SES_BOUNCE_LIMIT
"""
logger.info("bounce_records filter running")
#logger.info("bounce_records filter running")
#logger.info("message.recipients() befor blacklist_emails filter: %s" % recipiant_list)
blacklist_emails = list(set([record.email for record in BounceRecord.objects.filter(email__isnull=False).annotate(total=Count('email')).filter(total__gte=settings.SES_BOUNCE_LIMIT)]))
logger.info("message.recipients() befor blacklist_emails filter: %s" % recipiant_list)
blacklist_emails = list(set([record.email for record in BounceRecord.objects.filter(email__isnull=False).annotate(total=Count('email')).filter(total__gte=settings.SES_BOUNCE_LIMIT)]))
if blacklist_emails:
return filter_recipiants_with_blacklist(recipiant_list, blacklist_emails)
else:
return recipiant_list
def filter_recipiants_with_blacklist(recipiant_list, blacklist_emails):
"""
filter message recipiants with a list of email you dont want to email
filter message recipiants with a list of emails you dont want to email
"""
logger.info("blacklist_emails filter list: %s" % blacklist_emails)
filtered_recipiant_list = [email for email in recipiant_list if email not in blacklist_emails]
filtered_recipiant_list = [email for email in recipiant_list if email not in blacklist_emails]
logger.info("filtered_recipiant_list: %s" % filtered_recipiant_list)
return filtered_recipiant_list
def filter_recipiants_with_validater_email_domain(recipiant_list):
debug_flag = True
sent_list = [e.destination for e in SendRecord.objects.filter(destination__in=recipiant_list).distinct("destination")]
test_list = [e for e in recipiant_list if e not in sent_list]
for e in test_list:
if not validater_email_domain(e):
recipiant_list.remove(e)
return recipiant_list
def validater_email_domain(email):
if email.find("@") < 1:
return False
domain = email.split("@")[-1]
if BlackListedDomains.objects.filter(domain=domain).count() > 0:
return False
records = []
try:
records = dns.resolver.query(domain, 'MX')
except dns.resolver.NoNameservers as e:
return False
except dns.resolver.NoAnswer as e:
return False
except dns.resolver.NXDOMAIN as e:
return False
except dns.resolver.LifetimeTimeout as e:
return False
if len(records) < 1:
return False
return True
def emailIsValid(email):
resp = False
regex = re.compile(r'([A-Za-z0-9]+[.\-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(.[A-Z|a-z]{2,})+')
if re.fullmatch(regex, email):
resp = True
return resp
def validate_email(email):
if not emailIsValid(email):
return False
if BounceRecord.objects.filter(email=email).count() >= settings.SES_BOUNCE_LIMIT:
return False
if ComplaintRecord.objects.filter(email=email).count() > 0:
return False
return validater_email_domain(email)

View File

@ -249,6 +249,13 @@ def handle_bounce(request):
bounce_type = bounce_obj.get('bounceType')
bounce_subtype = bounce_obj.get('bounceSubType')
bounce_recipients = bounce_obj.get('bouncedRecipients', [])
logger.info(
u'Received bounce notification: feedbackId: %s, bounceType: %s, bounceSubType: %s',
feedback_id, bounce_type, bounce_subtype,
extra={
'notification': notification,
},
)
# create a BounceRecord so we can keep from sending to bad emails.
logger.info('create records')
@ -265,13 +272,6 @@ def handle_bounce(request):
reporting_mta = bounce_obj.get('reportingMTA', None),
)
logger.info(
u'Received bounce notification: feedbackId: %s, bounceType: %s, bounceSubType: %s',
feedback_id, bounce_type, bounce_subtype,
extra={
'notification': notification,
},
)
signals.bounce_received.send(
sender=handle_bounce,