class AmazonTransport(object): # pragma: no cover __slots__ = ('ephemeral', 'id', 'key', 'host', 'connection') def __init__(self, config): self.id = config.get('id') self.key = config.get('key') self.host = config.get('host', "email.us-east-1.amazonaws.com") self.connection = None def startup(self): self.connection = SESConnection(aws_access_key_id=self.id, aws_secret_access_key=self.key, host=self.host) def deliver(self, message): try: response = self.connection.send_raw_email( source=message.author.encode(), destinations=message.recipients.encode(), raw_message=str(message)) return (response['SendRawEmailResponse']['SendRawEmailResult'] ['MessageId'], response['SendRawEmailResponse'] ['ResponseMetadata']['RequestId']) except SESConnection.ResponseError: raise # TODO: Raise appropriate internal exception. # ['status', 'reason', 'body', 'request_id', 'error_code', 'error_message'] def shutdown(self): if self.connection: self.connection.close() self.connection = None
def ses_notify(pricedict, stocks): print "notify", pricedict, stocks lines = [] keys = pricedict.keys() keys.sort() if stocks: lines.append("big movers, %s" % ",".join(stocks)) for k in keys: v = pricedict[k] lines.append("%s : %.2f" % (k,v)) message = "\n".join(lines) print message import json with open("/home/yata/keys.json") as f: data = f.read() keys = json.loads(data) from boto.ses import SESConnection connection = SESConnection( aws_access_key_id=keys["AWS_ACCESS_KEY"], aws_secret_access_key=keys["AWS_SECRET_KEY"] ) connection.send_email("*****@*****.**", "stock update", message, ["*****@*****.**", "*****@*****.**"], )
def emit(self, record): """ Emit a record. Format the record and send it to the specified addressees. """ client = SESConnection(self.aws_key, self.aws_secret) message = MIMEMultipart('alternative') message.set_charset('UTF-8') message['Subject'] = self._encode_str(self.getSubject(record)) message['From'] = self._encode_str(self.fromaddr) message['To'] = self._convert_to_strings(self.toaddrs) from email.utils import formatdate body = self.format(record) body = "Date: {0}\r\n\r\n {1}".format(formatdate(), body) message.attach(MIMEText(self._encode_str(body), 'plain')) return client.send_raw_email(message.as_string(), self.fromaddr, destinations=self.toaddrs)
def __init__(self, aws_access_key, aws_secret_key): try: self.ses_conn = SESConnection(aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key) except: print "SES Connection was failed !!" exit()
def emit(self, record): """ Emit a record. Format the record and send it to the specified addressees. """ client = SESConnection(self.aws_key, self.aws_secret) message = MIMEMultipart('alternative') message.set_charset('UTF-8') message['Subject'] = self._encode_str(self.getSubject(record)) message['From'] = self._encode_str(self.fromaddr) message['To'] = self._convert_to_strings(self.toaddrs) from email.utils import formatdate body = self.format(record) body = "From: %s\r\n" \ "To: %s\r\n" \ "Subject: %s\r\n" \ "Date: %s\r\n\r\n" \ "%s" % ( self.fromaddr, ",".join(self.toaddrs), self.getSubject(record), formatdate(), body) message.attach(MIMEText(self._encode_str(body), 'plain')) return client.send_raw_email(message.as_string(), self.fromaddr, destinations=self.toaddrs)
def send_email(date_from, date_to, email=config['email']['default_to'], worklogs=None): worklogs = worklogs or get_worklogs(date_from, date_to) # put data into weeks weeks = {} for date in worklogs: # add issue date for worklog in worklogs[date]: issue, description = get_jira_issue(worklog['task_name']) if not issue: worklog['issue'] = worklog['task_name'] worklog['comment'] = '' continue worklog['issue'] = '<a href="%s" target="_blank">%s: %s</a>' % (issue.permalink(), str(issue), issue.fields.summary) worklog['comment'] = description week = '%i-%02i' % (date.year, date.isocalendar()[1]) if week not in weeks: weeks[week] = {} weeks[week][date] = worklogs[date] html = build_email(weeks, config['email']['template']) connection = SESConnection(aws_access_key_id=config['email']['aws']['access_key_id'], aws_secret_access_key=config['email']['aws']['secret_access_key']) subject = 'Hours report %s - %s' % (date_from.strftime('%m/%d'), date_to.strftime('%m/%d')) connection.send_email(config['email']['from'], subject, html, email, format='html')
def ses_email(config, to_address, subject, body): connection = SESConnection( aws_access_key_id=config['AWS_ACCESS_KEY_ID'], aws_secret_access_key=config['AWS_SECRET_ACCESS_KEY_ID']) from_address = '"SolutionNet" <{0}>'.format(config['FROM_EMAIL_ADDRESS']) connection.send_email(from_address, str(subject), str(escape(body)), str(to_address))
def dashboard(request): """ Graph SES send statistics over time. """ cache_key = 'vhash:django_ses_stats' cached_view = cache.get(cache_key) if cached_view: return cached_view region = RegionInfo(name=getattr(settings, 'AWS_SES_REGION_NAME', SESConnection.DefaultRegionName), endpoint=getattr(settings, 'AWS_SES_REGION_ENDPOINT', SESConnection.DefaultRegionEndpoint)) ses_conn = SESConnection( aws_access_key_id=getattr(settings, 'AWS_ACCESS_KEY_ID', None), aws_secret_access_key=getattr(settings, 'AWS_SECRET_ACCESS_KEY', None), region=region) quota_dict = ses_conn.get_send_quota() verified_emails_dict = ses_conn.list_verified_email_addresses() stats = ses_conn.get_send_statistics() quota = quota_parse(quota_dict) verified_emails = emails_parse(verified_emails_dict) ordered_data = stats_to_list(stats) summary = sum_stats(ordered_data) extra_context = { 'title': 'SES Statistics', 'datapoints': ordered_data, '24hour_quota': quota['Max24HourSend'], '24hour_sent': quota['SentLast24Hours'], '24hour_remaining': float(quota['Max24HourSend']) - float(quota['SentLast24Hours']), 'persecond_rate': quota['MaxSendRate'], 'verified_emails': verified_emails, 'summary': summary, 'access_key': ses_conn.gs_access_key_id, 'local_time': True if pytz else False, } response = render_to_response('django_ses/send_stats.html', extra_context, context_instance=RequestContext(request)) cache.set(cache_key, response, 60 * 15) # Cache for 15 minutes return response
def ses_email(config, to_address, subject, body): connection = SESConnection( aws_access_key_id=config['AWS_ACCESS_KEY_ID'], aws_secret_access_key=config['AWS_SECRET_ACCESS_KEY'], region=next(i for i in regions() if i.name == config['AWS_REGION'])) from_address = '"SolutionNet" <{0}>'.format(config['FROM_EMAIL_ADDRESS']) connection.send_email(from_address, str(subject), str(body), str(to_address))
def ses_email(config, to_address, subject, body): connection = SESConnection(aws_access_key_id=config['AWS_ACCESS_KEY_ID'], aws_secret_access_key=config['AWS_SECRET_ACCESS_KEY_ID']) from_address = '"SolutionNet" <{0}>'.format(config['FROM_EMAIL_ADDRESS']) connection.send_email(from_address, str(subject), str(escape(body)), str(to_address))
def dashboard(request): """ Graph SES send statistics over time. """ cache_key = 'vhash:django_ses_stats' cached_view = cache.get(cache_key) if cached_view: return cached_view region = RegionInfo(name=settings.AWS_SES_REGION_NAME, endpoint=settings.AWS_SES_REGION_ENDPOINT) ses_conn = SESConnection( aws_access_key_id=settings.ACCESS_KEY, aws_secret_access_key=settings.SECRET_KEY, region=region, proxy=settings.AWS_SES_PROXY, proxy_port=settings.AWS_SES_PROXY_PORT, ) quota_dict = ses_conn.get_send_quota() verified_emails_dict = ses_conn.list_verified_email_addresses() stats = ses_conn.get_send_statistics() quota = quota_parse(quota_dict) verified_emails = emails_parse(verified_emails_dict) ordered_data = stats_to_list(stats) summary = sum_stats(ordered_data) extra_context = { 'title': 'SES Statistics', 'datapoints': ordered_data, '24hour_quota': quota['Max24HourSend'], '24hour_sent': quota['SentLast24Hours'], '24hour_remaining': float(quota['Max24HourSend']) - float(quota['SentLast24Hours']), 'persecond_rate': quota['MaxSendRate'], 'verified_emails': verified_emails, 'summary': summary, 'access_key': ses_conn.gs_access_key_id, 'local_time': True, } response = render(request, 'django_ses/send_stats.html', extra_context) cache.set(cache_key, response, 60 * 15) # Cache for 15 minutes return response
def send_ses(self, sender_from, recipients, body): # SES Connection create aws_access_key = EXTERNAL_CONFIG['aws_access_key'] aws_secret_key = EXTERNAL_CONFIG['aws_secret_key'] from boto.ses import SESConnection ses_conn = SESConnection(aws_access_key, aws_secret_key) ret = ses_conn.send_raw_email(sender_from, body, destinations=[]) current_app.logger.debug('sent mail to %s by SES' % (str(recipients),)) return ret
def __init__(self, source, to_addresses, subject, **kw): self.ses = SESConnection() self._source = source self._to_addresses = to_addresses self._cc_addresses = None self._bcc_addresses = None self.subject = subject self.text = None self.html = None self.attachments = []
def send_mail_data(subject, body, format): connection = SESConnection(aws_access_key_id=AWS_ACCESS_KEY_ID, aws_secret_access_key=AWS_SECRET_ACCESS_KEY) try: emails = Mail.objects.all().values_list('email', flat=True) except Mail.DoesNotExist: emails = [] for i in range(0, len(emails), MAX_MAILS_PER_SEC): to_addresses = emails[i:(i + MAX_MAILS_PER_SEC)] connection.send_email(source=DEFAULT_EMAIL_SENDER, subject=subject, body=body, to_addresses=DEFAULT_EMAIL_SENDER, bcc_addresses=to_addresses, format=format) time.sleep(1)
def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key) except: if not self.fail_silently: raise
def dashboard(request): """ Graph SES send statistics over time. """ cache_key = 'vhash:django_ses_stats' cached_view = cache.get(cache_key) if cached_view: return cached_view region = RegionInfo( name=getattr(settings, 'AWS_SES_REGION_NAME', SESConnection.DefaultRegionName), endpoint=getattr(settings, 'AWS_SES_REGION_ENDPOINT', SESConnection.DefaultRegionEndpoint)) ses_conn = SESConnection( aws_access_key_id=getattr(settings, 'AWS_ACCESS_KEY_ID', None), aws_secret_access_key=getattr(settings, 'AWS_SECRET_ACCESS_KEY', None), region=region) quota_dict = ses_conn.get_send_quota() verified_emails_dict = ses_conn.list_verified_email_addresses() stats = ses_conn.get_send_statistics() quota = quota_parse(quota_dict) verified_emails = emails_parse(verified_emails_dict) ordered_data = stats_to_list(stats) summary = sum_stats(ordered_data) extra_context = { 'title': 'SES Statistics', 'datapoints': ordered_data, '24hour_quota': quota['Max24HourSend'], '24hour_sent': quota['SentLast24Hours'], '24hour_remaining': float(quota['Max24HourSend']) - float(quota['SentLast24Hours']), 'persecond_rate': quota['MaxSendRate'], 'verified_emails': verified_emails, 'summary': summary, 'access_key': ses_conn.gs_access_key_id, 'local_time': True if pytz else False, } response = render_to_response( 'django_ses/send_stats.html', extra_context, context_instance=RequestContext(request)) cache.set(cache_key, response, 60 * 15) # Cache for 15 minutes return response
class AWSSESSender: def __init__(self, aws_access_key, aws_secret_key): try: self.ses_conn = SESConnection(aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key) except: print "SES Connection was failed !!" exit() def send_email(self, sender, subject, body, recipient_list): if self.ses_conn != None: self.ses_conn.send_email(sender, subject, body, recipient_list) else: print "Connection object is null!!" def send_raw_email(self, sender, subject, body, recipient_list, attachment_path): msg = MIMEMultipart() msg['Subject'] = subject msg['From'] = sender to_list = "" for idx, data in enumerate(recipient_list): if idx < len(recipient_list) - 1: to_list += data + "," else: to_list += data msg['To'] = to_list msg.premable = 'Multipart Message.\n' # Assembling Mail body part = MIMEText(body) msg.attach(part) # Assembling Attachment part = MIMEApplication(open(attachment_path, 'rb').read()) part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachment_path)) msg.attach(part) # Send RAW email if self.ses_conn != None: self.ses_conn.send_raw_email(msg.as_string(), source=msg['From'], destinations=recipient_list) else: print "Connection object is null!!"
def dashboard(request): """ Graph SES send statistics over time. """ cache_key = 'vhash:django_ses_stats' cached_view = cache.get(cache_key) if cached_view: return cached_view region = RegionInfo( name=settings.AWS_SES_REGION_NAME, endpoint=settings.AWS_SES_REGION_ENDPOINT) ses_conn = SESConnection( aws_access_key_id=settings.ACCESS_KEY, aws_secret_access_key=settings.SECRET_KEY, region=region, proxy=settings.AWS_SES_PROXY, proxy_port=settings.AWS_SES_PROXY_PORT, ) quota_dict = ses_conn.get_send_quota() verified_emails_dict = ses_conn.list_verified_email_addresses() stats = ses_conn.get_send_statistics() quota = quota_parse(quota_dict) verified_emails = emails_parse(verified_emails_dict) ordered_data = stats_to_list(stats) summary = sum_stats(ordered_data) extra_context = { 'title': 'SES Statistics', 'datapoints': ordered_data, '24hour_quota': quota['Max24HourSend'], '24hour_sent': quota['SentLast24Hours'], '24hour_remaining': float(quota['Max24HourSend']) - float(quota['SentLast24Hours']), 'persecond_rate': quota['MaxSendRate'], 'verified_emails': verified_emails, 'summary': summary, 'access_key': ses_conn.gs_access_key_id, 'local_time': True, } response = render(request, 'django_ses/send_stats.html', extra_context) cache.set(cache_key, response, 60 * 15) # Cache for 15 minutes return response
def conn(self): if not self._conn: self._conn = SESConnection( aws_access_key_id=self.config['access_key'], aws_secret_access_key=self.config['secret_key'], ) return self._conn
class AmazonTransport(object): __slots__ = ('ephemeral', 'id', 'key', 'host', 'connection') def __init__(self, config): self.id = config.get('id') self.key = config.get('key') self.host = config.get('host', "email.us-east-1.amazonaws.com") self.connection = None def startup(self): self.connection = SESConnection( aws_access_key_id = self.id, aws_secret_access_key = self.key, host = self.host ) def deliver(self, message): try: response = self.connection.send_raw_email( source = message.author.encode(), destinations = message.recipients.encode(), raw_message = str(message) ) return ( response['SendRawEmailResponse']['SendRawEmailResult']['MessageId'], response['SendRawEmailResponse']['ResponseMetadata']['RequestId'] ) except SESConnection.ResponseError, err: raise # TODO: Raise appropriate internal exception.
def handle(self, *args, **options): verbosity = options.get('verbosity', 0) add_email = options.get('add', False) delete_email = options.get('delete', False) list_emails = options.get('list', False) access_key_id = settings.ACCESS_KEY access_key = settings.SECRET_KEY region = RegionInfo( name=settings.AWS_SES_REGION_NAME, endpoint=settings.AWS_SES_REGION_ENDPOINT) connection = SESConnection( aws_access_key_id=access_key_id, aws_secret_access_key=access_key, region=region) if add_email: if verbosity != '0': print "Adding email: %s" % add_email connection.verify_email_address(add_email) elif delete_email: if verbosity != '0': print "Removing email: %s" % delete_email connection.delete_verified_email_address(delete_email) elif list_emails: if verbosity != '0': print "Fetching list of verified emails:" response = connection.list_verified_email_addresses() emails = response['ListVerifiedEmailAddressesResponse'][ 'ListVerifiedEmailAddressesResult']['VerifiedEmailAddresses'] for email in emails: print email
def handle(self, *args, **options): verbosity = options.get('verbosity', 0) add_email = options.get('add', False) delete_email = options.get('delete', False) list_emails = options.get('list', False) access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None) access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None) api_endpoint = getattr(settings, 'AWS_SES_API_HOST', '%s.%s' % ( SESConnection.DefaultRegionName, SESConnection.DefaultRegionEndpoint)) connection = SESConnection( aws_access_key_id=access_key_id, aws_secret_access_key=access_key, host=api_endpoint, ) if add_email: if verbosity != '0': print "Adding email: %s" % add_email connection.verify_email_address(add_email) elif delete_email: if verbosity != '0': print "Removing email: %s" % delete_email connection.delete_verified_email_address(delete_email) elif list_emails: if verbosity != '0': print "Fetching list of verified emails:" response = connection.list_verified_email_addresses() emails = response['ListVerifiedEmailAddressesResponse']['ListVerifiedEmailAddressesResult']['VerifiedEmailAddresses'] for email in emails: print email
def notify_user(user_notification): email = user_notification.user.email email_body = _body(user_notification) email_subject = _subject(user_notification) if settings.DEBUG: print("Sending email: {0} with subject: {1} to: {2}".format( email_string, email_subject, email)) else: connection = SESConnection( aws_access_key_id=settings.AWS_ACCESS_KEY, aws_secret_access_key=settings.AWS_SECRET_KEY) connection.send_email( source="*****@*****.**", subject=email_subject, body=email_body, to_addresses=[email], format='html', cc_addresses=['*****@*****.**'])
def dashboard(request): """ Graph SES send statistics over time. """ cache_key = "vhash:django_ses_stats" cached_view = cache.get(cache_key) if cached_view: return cached_view region = RegionInfo(name=settings.AWS_SES_REGION_NAME, endpoint=settings.AWS_SES_REGION_ENDPOINT) ses_conn = SESConnection( aws_access_key_id=settings.ACCESS_KEY, aws_secret_access_key=settings.SECRET_KEY, region=region, boto_profile_name=settings.BOTO_PROFILE_NAME, ) quota_dict = ses_conn.get_send_quota() verified_emails_dict = ses_conn.list_verified_email_addresses() stats = ses_conn.get_send_statistics() quota = quota_parse(quota_dict) verified_emails = emails_parse(verified_emails_dict) ordered_data = stats_to_list(stats) summary = sum_stats(ordered_data) extra_context = { "title": "SES Statistics", "datapoints": ordered_data, "24hour_quota": quota["Max24HourSend"], "24hour_sent": quota["SentLast24Hours"], "24hour_remaining": float(quota["Max24HourSend"]) - float(quota["SentLast24Hours"]), "persecond_rate": quota["MaxSendRate"], "verified_emails": verified_emails, "summary": summary, "access_key": ses_conn.gs_access_key_id, "local_time": True if pytz else False, } response = render_to_response("django_ses/send_stats.html", extra_context, context_instance=RequestContext(request)) cache.set(cache_key, response, 60 * 15) # Cache for 15 minutes return response
def _send_email(email, amount, confirm_code): if not settings.DEBUG: context = { 'confirm_url': 'http://{0}{1}'.format( Site.objects.get_current().domain, reverse('main:confirm_pledge', args=[confirm_code])) } connection = SESConnection( aws_access_key_id=settings.AWS_ACCESS_KEY, aws_secret_access_key=settings.AWS_SECRET_KEY) connection.send_email( source="*****@*****.**", subject="Please confirm your pledge", body=render_to_string('pledge_email.html', context), to_addresses=[email], format='html', cc_addresses=['*****@*****.**']) else: print('Sent email to {0} about {1} with confirm code {2}'.format( email, amount, confirm_code))
def handle_noargs(self, **options): subject = 'hi krista' fromName = 'krista' fromAddress = '*****@*****.**' toAddressesStr = '*****@*****.**' textBody = 'hihihi' htmlBody = 'body yo yo yo' Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8') msg = MIMEMultipart('alternative') msg['Subject'] = subject msg['From'] = "" + str(fromName) + " <" + fromAddress + ">" msg['To'] = toAddressesStr connection = SESConnection(aws_access_key_id=settings.AWS_ACCESS_KEY, aws_secret_access_key=settings.AWS_SECRET_KEY) connection.send_email(fromName + " <" + fromAddress + ">", subject, body=htmlBody, to_addresses=toAddressesStr, text_body=textBody, format="html", return_path=fromAddress)
def handle(self, *args, **options): connection = SESConnection( aws_access_key_id=settings.ACCESS_KEY, aws_secret_access_key=settings.SECRET_KEY, proxy=settings.AWS_SES_PROXY, proxy_port=settings.AWS_SES_PROXY_PORT, proxy_user=settings.AWS_SES_PROXY_USER, proxy_pass=settings.AWS_SES_PROXY_PASS, ) stats = connection.get_send_statistics() data_points = stats_to_list(stats, localize=False) stats_dict = defaultdict(stat_factory) for data in data_points: attempts = int(data['DeliveryAttempts']) bounces = int(data['Bounces']) complaints = int(data['Complaints']) rejects = int(data['Rejects']) date = data['Timestamp'].split('T')[0] stats_dict[date]['delivery_attempts'] += attempts stats_dict[date]['bounces'] += bounces stats_dict[date]['complaints'] += complaints stats_dict[date]['rejects'] += rejects for k, v in stats_dict.items(): stat, created = SESStat.objects.get_or_create( date=k, defaults={ 'delivery_attempts': v['delivery_attempts'], 'bounces': v['bounces'], 'complaints': v['complaints'], 'rejects': v['rejects'], }) # If statistic is not new, modify data if values are different if not created and stat.delivery_attempts != v['delivery_attempts']: stat.delivery_attempts = v['delivery_attempts'] stat.bounces = v['bounces'] stat.complaints = v['complaints'] stat.rejects = v['rejects'] stat.save()
def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key, region=self._region, proxy=self._proxy, proxy_port=self._proxy_port, proxy_user=self._proxy_user, proxy_pass=self._proxy_pass, ) except Exception: if not self.fail_silently: raise
def handle(self, *args, **options): verbosity = options.get('verbosity', 0) add_email = options.get('add', False) delete_email = options.get('delete', False) list_emails = options.get('list', False) access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None) access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None) api_endpoint = getattr(settings, 'AWS_SES_API_HOST', SESConnection.DefaultHost) connection = SESConnection( aws_access_key_id=access_key_id, aws_secret_access_key=access_key, host=api_endpoint, ) if add_email: if verbosity != '0': print "Adding email: %s" % add_email connection.verify_email_address(add_email) elif delete_email: if verbosity != '0': print "Removing email: %s" % delete_email connection.delete_verified_email_address(delete_email) elif list_emails: if verbosity != '0': print "Fetching list of verified emails:" response = connection.list_verified_email_addresses() emails = response['ListVerifiedEmailAddressesResponse']['ListVerifiedEmailAddressesResult']['VerifiedEmailAddresses'] for email in emails: print email
def handle(self, *args, **options): verbosity = options.get("verbosity", 0) add_email = options.get("add", False) delete_email = options.get("delete", False) list_emails = options.get("list", False) access_key_id = getattr(settings, "AWS_ACCESS_KEY_ID", None) access_key = getattr(settings, "AWS_SECRET_ACCESS_KEY", None) connection = SESConnection(aws_access_key_id=access_key_id, aws_secret_access_key=access_key) if add_email: if verbosity != "0": print "Adding email: %s" % add_email connection.verify_email_address(add_email) elif delete_email: if verbosity != "0": print "Removing email: %s" % delete_email connection.delete_verified_email_address(delete_email) elif list_emails: if verbosity != "0": print "Fetching list of verified emails:" response = connection.list_verified_email_addresses() emails = response["ListVerifiedEmailAddressesResponse"]["ListVerifiedEmailAddressesResult"][ "VerifiedEmailAddresses" ] for email in emails: print email
def connect_ses(aws_access_key_id=None, aws_secret_access_key=None, **kwargs): """ :type aws_access_key_id: string :param aws_access_key_id: Your AWS Access Key ID :type aws_secret_access_key: string :param aws_secret_access_key: Your AWS Secret Access Key :rtype: :class:`boto.ses.SESConnection` :return: A connection to Amazon's SES """ from boto.ses import SESConnection return SESConnection(aws_access_key_id, aws_secret_access_key, **kwargs)
def handle(self, *args, **options): connection = SESConnection( aws_access_key_id=getattr(settings, "AWS_ACCESS_KEY_ID", None), aws_secret_access_key=getattr(settings, "AWS_SECRET_ACCESS_KEY", None), ) stats = connection.get_send_statistics() data_points = stats_to_list(stats, localize=False) stats_dict = defaultdict(stat_factory) for data in data_points: attempts = int(data["DeliveryAttempts"]) bounces = int(data["Bounces"]) complaints = int(data["Complaints"]) rejects = int(data["Rejects"]) date = data["Timestamp"].split("T")[0] stats_dict[date]["delivery_attempts"] += attempts stats_dict[date]["bounces"] += bounces stats_dict[date]["complaints"] += complaints stats_dict[date]["rejects"] += rejects for k, v in stats_dict.items(): stat, created = SESStat.objects.get_or_create( date=k, defaults={ "delivery_attempts": v["delivery_attempts"], "bounces": v["bounces"], "complaints": v["complaints"], "rejects": v["rejects"], }, ) # If statistic is not new, modify data if values are different if not created and stat.delivery_attempts != v["delivery_attempts"]: stat.delivery_attempts = v["delivery_attempts"] stat.bounces = v["bounces"] stat.complaints = v["complaints"] stat.rejects = v["rejects"] stat.save()
def send(subject,body,toAddressesStr,fromName,fromAddress,replacements): connection = SESConnection(aws_access_key_id=settings.AWS_ACCESS_KEY, aws_secret_access_key=settings.AWS_SECRET_KEY) ###Send Welcome Email htmlBody = "%s%s%s" % (HEADER,body,END) textBody = "%s\n\n\n%s" % (strip_tags(body), "Use link below to unsubscribe from these reminders: \n{{unsubscribe}}") textBody = textBody.replace(" ","") textBody = textBody.replace("’","'") textBody = textBody.replace("‘","'") textBody = textBody.replace("”",'"') textBody = textBody.replace("“",'"') for key, value in replacements.iteritems(): textBody = textBody.replace(key,value) htmlBody = htmlBody.replace(key,value) subject = subject.replace(key,value) connection.send_email(fromName + " <" + fromAddress + ">", subject, body=htmlBody, to_addresses=toAddressesStr, text_body=textBody, format="html", return_path=fromAddress)
def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key, host=self._api_endpoint ) except: if not self.fail_silently: raise
def send_invite(modeladmin, request, queryset): for r in queryset: h = hashlib.md5("%s%sfunkyfresh" % (request.user.id, r.email)) i = Invite.objects.create(owner=request.user, email=r.email, code=h.hexdigest()) r.delete() c = SESConnection(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) send_mail( "[muxlist] You're invited!", render_to_string('email/invite.html', { 'hostname': HOSTNAME, 'invite': i }), SERVER_EMAIL, [i.email])
class AmazonSMTPServer(smtpd.SMTPServer): amazonSES = SESConnection() def process_message(self, peer, mailfrom, rcpttos, data): if 'False' in rcpttos: logging.info('No recipient email') return data = email.message_from_string(data) # Amazon SES don't support 'Organization' header, which is created # by email_template module if 'Organization' in data: del data['Organization'] data = data.as_string() result = self.amazonSES.send_raw_email(mailfrom, data, rcpttos) logging.info('Email to %s sent' % rcpttos)
def send_mail(msg): global access_key global secret_key client = SESConnection( aws_access_key_id=access_key, aws_secret_access_key=secret_key) senders = msg["From"].split(",") recipients = msg["To"].split(',') for sender in senders: client.send_raw_email(msg.as_string(), sender, recipients) client.close()
def get_boto_ses_connection(): """ Shortcut for instantiating and returning a boto SESConnection object. :rtype: boto.ses.SESConnection :returns: A boto SESConnection object, from which email sending is done. """ access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None) access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None) api_endpoint = getattr(settings, 'AWS_SES_API_HOST', SESConnection.DefaultHost) return SESConnection( aws_access_key_id=access_key_id, aws_secret_access_key=access_key, host=api_endpoint, )
def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key, region=self._region, profile_name=self._boto_profile_name, ) except: if not self.fail_silently: raise
def handle(self, *args, **options): verbosity = options.get('verbosity', 0) add_email = options.get('add', False) delete_email = options.get('delete', False) list_emails = options.get('list', False) access_key_id = settings.ACCESS_KEY access_key = settings.SECRET_KEY region = RegionInfo( name=settings.AWS_SES_REGION_NAME, endpoint=settings.AWS_SES_REGION_ENDPOINT) proxy = settings.AWS_SES_PROXY proxy_port = settings.AWS_SES_PROXY_PORT proxy_user = settings.AWS_SES_PROXY_USER proxy_pass = settings.AWS_SES_PROXY_PASS connection = SESConnection( aws_access_key_id=access_key_id, aws_secret_access_key=access_key, region=region, proxy=proxy, proxy_port=proxy_port, proxy_user=proxy_user, proxy_pass=proxy_pass, ) if add_email: if verbosity != '0': print("Adding email: " + add_email) connection.verify_email_address(add_email) elif delete_email: if verbosity != '0': print("Removing email: " + delete_email) connection.delete_verified_email_address(delete_email) elif list_emails: if verbosity != '0': print("Fetching list of verified emails:") response = connection.list_verified_email_addresses() emails = response['ListVerifiedEmailAddressesResponse'][ 'ListVerifiedEmailAddressesResult']['VerifiedEmailAddresses'] for email in emails: print(email)
def mailsender(request): mail = request.FILES[u"file"].read() to = request.GET["to"] #split headers i = mail.find("\n\n") headers, mail = mail[:i], mail[i:] headers = headers.split("\n") allowed = {"MIME-Version", "Message-ID", "In-Reply-To", "Content-Type", "Date", "Subject", "From", "To", "Bcc", "Cc", "References"} from_ = None h = [] i=0 while i<len(headers): add = False header = headers[i][:headers[i].find(":")] if header in allowed: add = True if header == "From": from_ = headers[i][headers[i].find(":")+1:].strip() while True: if add: h.append(headers[i]) i += 1 if i>=len(headers) or headers[i][0] not in " \t": break mail = "\n".join(h) + mail #find from email i = from_.find("<") if i != -1: from_ = from_[i+1:] from_ = from_[:from_.find(">")] #logger.info("headers: %s", str(headers)) #logger.info("h: %s", str(h)) logger.info("Mail from %s to %s recieved", from_, to) # Only allow sending from altekamereren domains and registered users. if not from_.endswith("@altekamereren.org") \ and not from_.endswith("@altekamereren.com") \ and User.objects.filter(email=from_).exists(): logger.info("Sender not accepted.") return HttpResponse(status=403) to = to.replace(u"flojt", u"flöjt") reciever = to.split("@")[0] if reciever in ak.sections: user_emails = [user.email for user in User.objects.filter( instrument__in=ak.section_to_short_instruments[reciever], is_active=True)] logger.info("Sending to section %s: %s", to, str(user_emails)) elif reciever == u"infolistan": reciever = [user.email for user in User.objects.filter(is_active=True)] logger.info("Sending to infolistan: %s", str(reciever)) else: logger.info("List not accepted.") return HttpResponse(status=400) from django.conf import settings from boto.ses import SESConnection from boto.exception import BotoServerError access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None) access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None) api_endpoint = getattr(settings, 'AWS_SES_API_HOST', SESConnection.DefaultHost) connection = SESConnection( aws_access_key_id=access_key_id, aws_secret_access_key=access_key, host=api_endpoint, ) if not user_emails: return HttpResponse(status=400) try: connection.send_raw_email(mail, settings.ADMINS[0][1], user_emails) except BotoServerError as e: i = e.body.find("<Message>") message = e.body[i+len("<Message>"):] message = message[:message.find("</Message>")] if message == "Email address is not verified.": if MailVerificationSent.objects.filter(email=from_, sent__gte=datetime.datetime.now() - datetime.timedelta(days=1) ).exists(): connection.verify_email_address(from_) logger.error("Sending verify mail to: %s", from_) MailVerificationSent(email=from_).save() else: logger.error("Verify mail already sent today: %s", from_) return HttpResponse(status=444) else: raise return HttpResponse()
def send_email(fromaddr, toaddrs, subject, txtdata): from boto.ses import SESConnection connection = SESConnection( aws_access_key_id=keys["AWS_ACCESS_KEY"], aws_secret_access_key=keys["AWS_SECRET_KEY"]) connection.send_email(fromaddr, subject, txtdata, toaddrs)
class SESBackend(BaseEmailBackend): """A Django Email backend that uses Amazon's Simple Email Service. """ def __init__(self, fail_silently=False, aws_access_key=None, aws_secret_key=None, aws_region_name=None, aws_region_endpoint=None, aws_auto_throttle=None, dkim_domain=None, dkim_key=None, dkim_selector=None, dkim_headers=None, **kwargs): super(SESBackend, self).__init__(fail_silently=fail_silently, **kwargs) self._access_key_id = aws_access_key or settings.ACCESS_KEY self._access_key = aws_secret_key or settings.SECRET_KEY self._region = RegionInfo( name=aws_region_name or settings.AWS_SES_REGION_NAME, endpoint=aws_region_endpoint or settings.AWS_SES_REGION_ENDPOINT) self._throttle = aws_auto_throttle or settings.AWS_SES_AUTO_THROTTLE self.dkim_domain = dkim_domain or settings.DKIM_DOMAIN self.dkim_key = dkim_key or settings.DKIM_PRIVATE_KEY self.dkim_selector = dkim_selector or settings.DKIM_SELECTOR self.dkim_headers = dkim_headers or settings.DKIM_HEADERS self.connection = None def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key, region=self._region, ) except: if not self.fail_silently: raise def close(self): """Close any open HTTP connections to the API server. """ try: self.connection.close() self.connection = None except: if not self.fail_silently: raise def send_messages(self, email_messages): """Sends one or more EmailMessage objects and returns the number of email messages sent. """ if not email_messages: return new_conn_created = self.open() if not self.connection: # Failed silently return num_sent = 0 source = settings.AWS_SES_RETURN_PATH for message in email_messages: # Automatic throttling. Assumes that this is the only SES client # currently operating. The AWS_SES_AUTO_THROTTLE setting is a # factor to apply to the rate limit, with a default of 0.5 to stay # well below the actual SES throttle. # Set the setting to 0 or None to disable throttling. if self._throttle: global recent_send_times now = datetime.now() # Get and cache the current SES max-per-second rate limit # returned by the SES API. rate_limit = self.get_rate_limit() # Prune from recent_send_times anything more than a few seconds # ago. Even though SES reports a maximum per-second, the way # they enforce the limit may not be on a one-second window. # To be safe, we use a two-second window (but allow 2 times the # rate limit) and then also have a default rate limit factor of # 0.5 so that we really limit the one-second amount in two # seconds. window = 2.0 # seconds window_start = now - timedelta(seconds=window) new_send_times = [] for time in recent_send_times: if time > window_start: new_send_times.append(time) recent_send_times = new_send_times # If the number of recent send times in the last 1/_throttle # seconds exceeds the rate limit, add a delay. # Since I'm not sure how Amazon determines at exactly what # point to throttle, better be safe than sorry and let in, say, # half of the allowed rate. if len(new_send_times) > rate_limit * window * self._throttle: # Sleep the remainder of the window period. delta = now - new_send_times[0] total_seconds = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6 delay = window - total_seconds if delay > 0: sleep(delay) recent_send_times.append(now) # end of throttling try: response = self.connection.send_raw_email( source=source or message.from_email, destinations=message.recipients(), raw_message=unicode(dkim_sign(message.message().as_string(), dkim_key=self.dkim_key, dkim_domain=self.dkim_domain, dkim_selector=self.dkim_selector, dkim_headers=self.dkim_headers, ), 'utf-8') ) message.extra_headers['status'] = 200 message.extra_headers['message_id'] = response[ 'SendRawEmailResponse']['SendRawEmailResult']['MessageId'] message.extra_headers['request_id'] = response[ 'SendRawEmailResponse']['ResponseMetadata']['RequestId'] num_sent += 1 except SESConnection.ResponseError, err: # Store failure information so to post process it if required error_keys = ['status', 'reason', 'body', 'request_id', 'error_code', 'error_message'] for key in error_keys: message.extra_headers[key] = getattr(err, key, None) if not self.fail_silently: raise if new_conn_created: self.close() return num_sent
""" import mimetypes from email import encoders from email.utils import COMMASPACE from email.mime.multipart import MIMEMultipart from email.mime.audio import MIMEAudio from email.mime.base import MIMEBase from email.mime.image import MIMEImage from email.mime.text import MIMEText from boto.ses import SESConnection AWS_ACCESS_KEY = 'PUT ACCESS KEY HERE' AWS_SECRET_KEY = 'PUT SECRET KEY HERE' connection = SESConnection(AWS_ACCESS_KEY, AWS_SECRET_KEY) class SESMessage(object): """ Usage: msg = SESMessage('*****@*****.**', '*****@*****.**', 'The subject') msg.text = 'Text body' msg.html = 'HTML body' msg.send() """ def __init__(self, source, to_addresses, subject, **kw): self.ses = connection
class SESBackend(BaseEmailBackend): """A Django Email backend that uses Amazon's Simple Email Service. """ def __init__(self, fail_silently=False, *args, **kwargs): super(SESBackend, self).__init__(fail_silently=fail_silently, *args, **kwargs) self._access_key_id = getattr(settings, "AWS_ACCESS_KEY_ID", None) self._access_key = getattr(settings, "AWS_SECRET_ACCESS_KEY", None) self._api_endpoint = getattr(settings, "AWS_SES_API_HOST", SESConnection.DefaultHost) self.connection = None def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key, host=self._api_endpoint ) except: if not self.fail_silently: raise def close(self): """Close any open HTTP connections to the API server. """ try: self.connection.close() self.connection = None except: if not self.fail_silently: raise def send_messages(self, email_messages): """Sends one or more EmailMessage objects and returns the number of email messages sent. """ if not email_messages: return new_conn_created = self.open() if not self.connection: # Failed silently return num_sent = 0 for message in email_messages: try: response = self.connection.send_raw_email( source=message.from_email, destinations=message.recipients(), raw_message=message.message().as_string(), ) message.extra_headers["status"] = 200 message.extra_headers["message_id"] = response["SendRawEmailResponse"]["SendRawEmailResult"][ "MessageId" ] message.extra_headers["request_id"] = response["SendRawEmailResponse"]["ResponseMetadata"]["RequestId"] num_sent += 1 except SESConnection.ResponseError, err: # Store failure information so you can post process it if required error_keys = ["status", "reason", "body", "request_id", "error_code", "error_message"] for key in error_keys: message.extra_headers[key] = getattr(err, key, None) if not self.fail_silently: raise if new_conn_created: self.close() return num_sent
class SesSender(object): logger = None def run(self): self.init_log() self.init_signer() try: self.log("Args: %r" % argv) self.log("Env: %r" % dict(environ)) self.get_parties() self.get_credentials() self.make_connection() self.process_message() self.send_message() except Exception: self.abort('Unspecified error',1) def get_parties(self): try: self.sender = argv[1] self.recipients = argv[2:] except Exception: self.abort('Missing Sender / Recipients',2) def get_credentials(self): try: self.aws_id = environ['AWS_ACCESS_KEY_ID'] self.aws_key = environ['AWS_SECRET_KEY'] assert self.aws_id is not None assert self.aws_key is not None except Exception: self.abort('Missing AWS Credentials',3) def make_connection(self): try: self.conn = SESConnection(self.aws_id,self.aws_key) except Exception: self.abort('Failed to establish connection',4) def process_message(self): try: msg = stdin.read() assert msg[:4] == 'From' msg = self.sanitize_headers(msg) envelope,msg = msg.split('\n',1) self.msg = self.sign_message(msg) self.log('Sender: %r' % self.sender) self.log('Recipients: %r' % self.recipients) self.log('Message:\n' + msg) except Exception: self.abort('Failed to process message text',5) def sanitize_headers(self, msg): msg_obj = Parser().parsestr(msg) for hdr in msg_obj.keys(): if hdr not in aws_allowed_headers and not hdr.startswith('X-'): del msg_obj[hdr] return str(msg_obj) def sign_message(self, msg): if self.dkim: return DKIM(msg).sign(self.dkim_selector, self.dkim_domain, self.dkim_private_key, canonicalize=('relaxed', 'simple'), include_headers=dkim_include_headers) + msg else: return msg def send_message(self): try: self.conn.send_raw_email( source=self.sender, raw_message=self.msg, destinations=self.recipients ) except BotoServerError, bse: if 'InvalidTokenId' in bse.body: self.abort('Bad AWS Credentials (token)',6) if 'SignatureDoesNotMatch' in bse.body: self.abort('Bad AWS Credentials (signature)',6) if bse.error_code == 'Throttling': self.abort('Failed to actually deliver message: quota exceeded',9) self.abort('Failed to actually deliver message:',7) except Exception: self.abort('Failed to actually deliver message:',7)
def startup(self): self.connection = SESConnection( aws_access_key_id = self.id, aws_secret_access_key = self.key, host = self.host )
def get_client(self): if not self.client: self.client = SESConnection(self.aws_key, self.aws_secret) return self.client
class SESBackend(BaseEmailBackend): """A Django Email backend that uses Amazon's Simple Email Service. """ def __init__(self, fail_silently=False, aws_access_key=None, aws_secret_key=None, aws_region_name=None, aws_region_endpoint=None, aws_auto_throttle=None, dkim_domain=None, dkim_key=None, dkim_selector=None, dkim_headers=None, proxy=None, proxy_port=None, proxy_user=None, proxy_pass=None, **kwargs): super(SESBackend, self).__init__(fail_silently=fail_silently, **kwargs) self._access_key_id = aws_access_key or settings.ACCESS_KEY self._access_key = aws_secret_key or settings.SECRET_KEY self._region = RegionInfo(name=aws_region_name or settings.AWS_SES_REGION_NAME, endpoint=aws_region_endpoint or settings.AWS_SES_REGION_ENDPOINT) self._throttle = aws_auto_throttle or settings.AWS_SES_AUTO_THROTTLE self._proxy = proxy or settings.AWS_SES_PROXY self._proxy_port = proxy_port or settings.AWS_SES_PROXY_PORT self._proxy_user = proxy_user or settings.AWS_SES_PROXY_USER self._proxy_pass = proxy_pass or settings.AWS_SES_PROXY_PASS self.dkim_domain = dkim_domain or settings.DKIM_DOMAIN self.dkim_key = dkim_key or settings.DKIM_PRIVATE_KEY self.dkim_selector = dkim_selector or settings.DKIM_SELECTOR self.dkim_headers = dkim_headers or settings.DKIM_HEADERS self.connection = None def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key, region=self._region, proxy=self._proxy, proxy_port=self._proxy_port, proxy_user=self._proxy_user, proxy_pass=self._proxy_pass, ) except Exception: if not self.fail_silently: raise def close(self): """Close any open HTTP connections to the API server. """ try: self.connection.close() self.connection = None except Exception: if not self.fail_silently: raise def send_messages(self, email_messages): """Sends one or more EmailMessage objects and returns the number of email messages sent. """ if not email_messages: return new_conn_created = self.open() if not self.connection: # Failed silently return num_sent = 0 source = settings.AWS_SES_RETURN_PATH for message in email_messages: # SES Configuration sets. If the AWS_SES_CONFIGURATION_SET setting # is not None, append the appropriate header to the message so that # SES knows which configuration set it belongs to. # # 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. if (settings.AWS_SES_CONFIGURATION_SET and 'X-SES-CONFIGURATION-SET' not in message.extra_headers): if callable(settings.AWS_SES_CONFIGURATION_SET): message.extra_headers[ 'X-SES-CONFIGURATION-SET'] = settings.AWS_SES_CONFIGURATION_SET( message, dkim_domain=self.dkim_domain, dkim_key=self.dkim_key, dkim_selector=self.dkim_selector, dkim_headers=self.dkim_headers) else: message.extra_headers[ 'X-SES-CONFIGURATION-SET'] = settings.AWS_SES_CONFIGURATION_SET # Automatic throttling. Assumes that this is the only SES client # currently operating. The AWS_SES_AUTO_THROTTLE setting is a # factor to apply to the rate limit, with a default of 0.5 to stay # well below the actual SES throttle. # Set the setting to 0 or None to disable throttling. if self._throttle: global recent_send_times now = datetime.now() # Get and cache the current SES max-per-second rate limit # returned by the SES API. rate_limit = self.get_rate_limit() logger.debug(u"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 # they enforce the limit may not be on a one-second window. # To be safe, we use a two-second window (but allow 2 times the # rate limit) and then also have a default rate limit factor of # 0.5 so that we really limit the one-second amount in two # seconds. window = 2.0 # seconds window_start = now - timedelta(seconds=window) new_send_times = [] for time in recent_send_times: if time > window_start: new_send_times.append(time) recent_send_times = new_send_times # If the number of recent send times in the last 1/_throttle # seconds exceeds the rate limit, add a delay. # Since I'm not sure how Amazon determines at exactly what # point to throttle, better be safe than sorry and let in, say, # half of the allowed rate. if len(new_send_times) > rate_limit * window * self._throttle: # Sleep the remainder of the window period. delta = now - new_send_times[0] total_seconds = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6 delay = window - total_seconds if delay > 0: sleep(delay) recent_send_times.append(now) # end of throttling try: response = self.connection.send_raw_email( source=source or message.from_email, destinations=message.recipients(), raw_message=dkim_sign(message.message().as_string(), dkim_key=self.dkim_key, dkim_domain=self.dkim_domain, dkim_selector=self.dkim_selector, dkim_headers=self.dkim_headers)) message.extra_headers['status'] = 200 message.extra_headers['message_id'] = response[ 'SendRawEmailResponse']['SendRawEmailResult']['MessageId'] message.extra_headers['request_id'] = response[ 'SendRawEmailResponse']['ResponseMetadata']['RequestId'] num_sent += 1 if 'X-SES-CONFIGURATION-SET' in message.extra_headers: logger.debug( u"send_messages.sent from='{}' recipients='{}' message_id='{}' request_id='{}' ses-configuration-set='{}'" .format( message.from_email, ", ".join(message.recipients()), message.extra_headers['message_id'], message.extra_headers['request_id'], message.extra_headers['X-SES-CONFIGURATION-SET'])) else: logger.debug( u"send_messages.sent from='{}' recipients='{}' message_id='{}' request_id='{}'" .format(message.from_email, ", ".join(message.recipients()), message.extra_headers['message_id'], message.extra_headers['request_id'])) except SESConnection.ResponseError as err: # Store failure information so to post process it if required error_keys = [ 'status', 'reason', 'body', 'request_id', 'error_code', 'error_message' ] for key in error_keys: message.extra_headers[key] = getattr(err, key, None) if not self.fail_silently: raise if new_conn_created: self.close() return num_sent def get_rate_limit(self): if self._access_key_id in cached_rate_limits: return cached_rate_limits[self._access_key_id] new_conn_created = self.open() if not self.connection: raise Exception( "No connection is available to check current SES rate limit.") try: quota_dict = self.connection.get_send_quota() max_per_second = quota_dict['GetSendQuotaResponse'][ 'GetSendQuotaResult']['MaxSendRate'] ret = float(max_per_second) cached_rate_limits[self._access_key_id] = ret return ret finally: if new_conn_created: self.close()
class SESBackend(BaseEmailBackend): """A Django Email backend that uses Amazon's Simple Email Service. """ def __init__(self, fail_silently=False, aws_access_key=None, aws_secret_key=None, aws_region_name=None, aws_region_endpoint=None, aws_auto_throttle=None, dkim_domain=None, dkim_key=None, dkim_selector=None, dkim_headers=None, **kwargs): super(SESBackend, self).__init__(fail_silently=fail_silently, **kwargs) self._access_key_id = aws_access_key or settings.ACCESS_KEY self._access_key = aws_secret_key or settings.SECRET_KEY self._region = RegionInfo(name=aws_region_name or settings.AWS_SES_REGION_NAME, endpoint=aws_region_endpoint or settings.AWS_SES_REGION_ENDPOINT) self._throttle = aws_auto_throttle or settings.AWS_SES_AUTO_THROTTLE self.dkim_domain = dkim_domain or settings.DKIM_DOMAIN self.dkim_key = dkim_key or settings.DKIM_PRIVATE_KEY self.dkim_selector = dkim_selector or settings.DKIM_SELECTOR self.dkim_headers = dkim_headers or settings.DKIM_HEADERS self.connection = None def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key, region=self._region, ) except: if not self.fail_silently: raise def close(self): """Close any open HTTP connections to the API server. """ try: self.connection.close() self.connection = None except: if not self.fail_silently: raise def send_messages(self, email_messages): """Sends one or more EmailMessage objects and returns the number of email messages sent. """ if not email_messages: return new_conn_created = self.open() if not self.connection: # Failed silently return num_sent = 0 source = settings.AWS_SES_RETURN_PATH for message in email_messages: # Automatic throttling. Assumes that this is the only SES client # currently operating. The AWS_SES_AUTO_THROTTLE setting is a # factor to apply to the rate limit, with a default of 0.5 to stay # well below the actual SES throttle. # Set the setting to 0 or None to disable throttling. if self._throttle: global recent_send_times now = datetime.now() # Get and cache the current SES max-per-second rate limit # returned by the SES API. rate_limit = self.get_rate_limit() # Prune from recent_send_times anything more than a few seconds # ago. Even though SES reports a maximum per-second, the way # they enforce the limit may not be on a one-second window. # To be safe, we use a two-second window (but allow 2 times the # rate limit) and then also have a default rate limit factor of # 0.5 so that we really limit the one-second amount in two # seconds. window = 2.0 # seconds window_start = now - timedelta(seconds=window) new_send_times = [] for time in recent_send_times: if time > window_start: new_send_times.append(time) recent_send_times = new_send_times # If the number of recent send times in the last 1/_throttle # seconds exceeds the rate limit, add a delay. # Since I'm not sure how Amazon determines at exactly what # point to throttle, better be safe than sorry and let in, say, # half of the allowed rate. if len(new_send_times) > rate_limit * window * self._throttle: # Sleep the remainder of the window period. delta = now - new_send_times[0] total_seconds = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6 delay = window - total_seconds if delay > 0: sleep(delay) recent_send_times.append(now) # end of throttling try: response = self.connection.send_raw_email( source=source or message.from_email, destinations=message.recipients(), raw_message=unicode( dkim_sign( message.message().as_string(), dkim_key=self.dkim_key, dkim_domain=self.dkim_domain, dkim_selector=self.dkim_selector, dkim_headers=self.dkim_headers, ), 'utf-8')) message.extra_headers['status'] = 200 message.extra_headers['message_id'] = response[ 'SendRawEmailResponse']['SendRawEmailResult']['MessageId'] message.extra_headers['request_id'] = response[ 'SendRawEmailResponse']['ResponseMetadata']['RequestId'] num_sent += 1 except SESConnection.ResponseError, err: # Store failure information so to post process it if required error_keys = [ 'status', 'reason', 'body', 'request_id', 'error_code', 'error_message' ] for key in error_keys: message.extra_headers[key] = getattr(err, key, None) if not self.fail_silently: raise if new_conn_created: self.close() return num_sent
class SESBackend(BaseEmailBackend): """A Django Email backend that uses Amazon's Simple Email Service. """ def __init__(self, fail_silently=False, *args, **kwargs): super(SESBackend, self).__init__(fail_silently=fail_silently, *args, **kwargs) self._access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None) self._access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None) self._api_endpoint = getattr(settings, 'AWS_SES_API_HOST', SESConnection.DefaultHost) self.connection = None def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key, host=self._api_endpoint, ) except: if not self.fail_silently: raise def close(self): """Close any open HTTP connections to the API server. """ try: self.connection.close() self.connection = None except: if not self.fail_silently: raise def send_messages(self, email_messages): """Sends one or more EmailMessage objects and returns the number of email messages sent. """ if not email_messages: return new_conn_created = self.open() if not self.connection: # Failed silently return num_sent = 0 for message in email_messages: try: response = self.connection.send_raw_email( source=message.from_email, destinations=message.recipients(), raw_message=message.message().as_string(), ) message.extra_headers['status'] = 200 message.extra_headers['message_id'] = response[ 'SendRawEmailResponse']['SendRawEmailResult']['MessageId'] message.extra_headers['request_id'] = response[ 'SendRawEmailResponse']['ResponseMetadata']['RequestId'] num_sent += 1 except SESConnection.ResponseError, err: # Store failure information so you can post process it if required error_keys = [ 'status', 'reason', 'body', 'request_id', 'error_code', 'error_message' ] for key in error_keys: message.extra_headers[key] = getattr(err, key, None) if not self.fail_silently: raise if new_conn_created: self.close() return num_sent
def make_connection(self): try: self.conn = SESConnection(self.aws_id,self.aws_key) except Exception: self.abort('Failed to establish connection',4)
class SESBackend(BaseEmailBackend): """A Django Email backend that uses Amazon's Simple Email Service. """ def __init__(self, fail_silently=False, aws_access_key=None, aws_secret_key=None, aws_region_name=None, aws_region_endpoint=None, aws_auto_throttle=None, dkim_domain=None, dkim_key=None, dkim_selector=None, dkim_headers=None, proxy=None, proxy_port=None, proxy_user=None, proxy_pass=None, **kwargs): super(SESBackend, self).__init__(fail_silently=fail_silently, **kwargs) self._access_key_id = aws_access_key or settings.ACCESS_KEY self._access_key = aws_secret_key or settings.SECRET_KEY self._region = RegionInfo( name=aws_region_name or settings.AWS_SES_REGION_NAME, endpoint=aws_region_endpoint or settings.AWS_SES_REGION_ENDPOINT) self._throttle = aws_auto_throttle or settings.AWS_SES_AUTO_THROTTLE self._proxy = proxy or settings.AWS_SES_PROXY self._proxy_port = proxy_port or settings.AWS_SES_PROXY_PORT self._proxy_user = proxy_user or settings.AWS_SES_PROXY_USER self._proxy_pass = proxy_pass or settings.AWS_SES_PROXY_PASS self.dkim_domain = dkim_domain or settings.DKIM_DOMAIN self.dkim_key = dkim_key or settings.DKIM_PRIVATE_KEY self.dkim_selector = dkim_selector or settings.DKIM_SELECTOR self.dkim_headers = dkim_headers or settings.DKIM_HEADERS self.connection = None def open(self): """Create a connection to the AWS API server. This can be reused for sending multiple emails. """ if self.connection: return False try: self.connection = SESConnection( aws_access_key_id=self._access_key_id, aws_secret_access_key=self._access_key, region=self._region, proxy=self._proxy, proxy_port=self._proxy_port, proxy_user=self._proxy_user, proxy_pass=self._proxy_pass, ) except Exception: if not self.fail_silently: raise def close(self): """Close any open HTTP connections to the API server. """ try: self.connection.close() self.connection = None except Exception: if not self.fail_silently: raise def send_messages(self, email_messages): """Sends one or more EmailMessage objects and returns the number of email messages sent. """ if not email_messages: return new_conn_created = self.open() if not self.connection: # Failed silently return num_sent = 0 source = settings.AWS_SES_RETURN_PATH for message in email_messages: # SES Configuration sets. If the AWS_SES_CONFIGURATION_SET setting # is not None, append the appropriate header to the message so that # SES knows which configuration set it belongs to. # # 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. if (settings.AWS_SES_CONFIGURATION_SET and 'X-SES-CONFIGURATION-SET' not in message.extra_headers): if callable(settings.AWS_SES_CONFIGURATION_SET): message.extra_headers[ 'X-SES-CONFIGURATION-SET'] = settings.AWS_SES_CONFIGURATION_SET( message, dkim_domain=self.dkim_domain, dkim_key=self.dkim_key, dkim_selector=self.dkim_selector, dkim_headers=self.dkim_headers ) else: message.extra_headers[ 'X-SES-CONFIGURATION-SET'] = settings.AWS_SES_CONFIGURATION_SET # Automatic throttling. Assumes that this is the only SES client # currently operating. The AWS_SES_AUTO_THROTTLE setting is a # factor to apply to the rate limit, with a default of 0.5 to stay # well below the actual SES throttle. # Set the setting to 0 or None to disable throttling. if self._throttle: global recent_send_times now = datetime.now() # Get and cache the current SES max-per-second rate limit # returned by the SES API. rate_limit = self.get_rate_limit() logger.debug(u"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 # they enforce the limit may not be on a one-second window. # To be safe, we use a two-second window (but allow 2 times the # rate limit) and then also have a default rate limit factor of # 0.5 so that we really limit the one-second amount in two # seconds. window = 2.0 # seconds window_start = now - timedelta(seconds=window) new_send_times = [] for time in recent_send_times: if time > window_start: new_send_times.append(time) recent_send_times = new_send_times # If the number of recent send times in the last 1/_throttle # seconds exceeds the rate limit, add a delay. # Since I'm not sure how Amazon determines at exactly what # point to throttle, better be safe than sorry and let in, say, # half of the allowed rate. if len(new_send_times) > rate_limit * window * self._throttle: # Sleep the remainder of the window period. delta = now - new_send_times[0] total_seconds = (delta.microseconds + (delta.seconds + delta.days * 24 * 3600) * 10**6) / 10**6 delay = window - total_seconds if delay > 0: sleep(delay) recent_send_times.append(now) # end of throttling try: response = self.connection.send_raw_email( source=source or message.from_email, destinations=message.recipients(), raw_message=dkim_sign(message.message().as_string(), dkim_key=self.dkim_key, dkim_domain=self.dkim_domain, dkim_selector=self.dkim_selector, dkim_headers=self.dkim_headers) ) message.extra_headers['status'] = 200 message.extra_headers['message_id'] = response[ 'SendRawEmailResponse']['SendRawEmailResult']['MessageId'] message.extra_headers['request_id'] = response[ 'SendRawEmailResponse']['ResponseMetadata']['RequestId'] num_sent += 1 if 'X-SES-CONFIGURATION-SET' in message.extra_headers: logger.debug(u"send_messages.sent from='{}' recipients='{}' message_id='{}' request_id='{}' ses-configuration-set='{}'".format( message.from_email, ", ".join(message.recipients()), message.extra_headers['message_id'], message.extra_headers['request_id'], message.extra_headers['X-SES-CONFIGURATION-SET'] )) else: logger.debug(u"send_messages.sent from='{}' recipients='{}' message_id='{}' request_id='{}'".format( message.from_email, ", ".join(message.recipients()), message.extra_headers['message_id'], message.extra_headers['request_id'] )) except SESConnection.ResponseError as err: # Store failure information so to post process it if required error_keys = ['status', 'reason', 'body', 'request_id', 'error_code', 'error_message'] for key in error_keys: message.extra_headers[key] = getattr(err, key, None) if not self.fail_silently: raise if new_conn_created: self.close() return num_sent def get_rate_limit(self): if self._access_key_id in cached_rate_limits: return cached_rate_limits[self._access_key_id] new_conn_created = self.open() if not self.connection: raise Exception( "No connection is available to check current SES rate limit.") try: quota_dict = self.connection.get_send_quota() max_per_second = quota_dict['GetSendQuotaResponse'][ 'GetSendQuotaResult']['MaxSendRate'] ret = float(max_per_second) cached_rate_limits[self._access_key_id] = ret return ret finally: if new_conn_created: self.close()
class SESMessage(object): """ Usage: msg = SESMessage('*****@*****.**', '*****@*****.**', 'The subject') msg.text = 'Text body' msg.html = 'HTML body' msg.send() """ def __init__(self, source, to_addresses, subject, **kw): self.ses = SESConnection() self._source = source self._to_addresses = to_addresses self._cc_addresses = None self._bcc_addresses = None self.subject = subject self.text = None self.html = None self.attachments = [] def send(self): if not self.ses: raise Exception, 'No connection found' if (self.text and not self.html and not self.attachments) or \ (self.html and not self.text and not self.attachments): return self.ses.send_email(self._source, self.subject, self.text or self.html, self._to_addresses, self._cc_addresses, self._bcc_addresses, format='text' if self.text else 'html') else: if not self.attachments: message = MIMEMultipart('alternative') message['Subject'] = self.subject message['From'] = self._source if isinstance(self._to_addresses, (list, tuple)): message['To'] = COMMASPACE.join(self._to_addresses) else: message['To'] = self._to_addresses message.attach(MIMEText(self.text, 'plain')) message.attach(MIMEText(self.html, 'html')) else: raise NotImplementedError, 'SES does not currently allow ' + \ 'messages with attachments.' # message = MIMEMultipart() # # message_alt = MIMEMultipart('alternative') # # if self.text: # message_alt.attach(MIMEText(self.text, 'plain')) # if self.html: # message_alt.attach(MIMEText(self.html, 'html')) # # message.attach(message_alt) # # message['Subject'] = self.subject # message['From'] = self._source # if isinstance(self._to_addresses, (list, tuple)): # message['To'] = COMMASPACE.join(self._to_addresses) # else: # message['To'] = self._to_addresses # message.preamble = 'You will not see this in a MIME-aware mail reader.\n' # print 'message: ', message.as_string() # for attachment in self.attachments: # # Guess the content type based on the file's extension. Encoding # # will be ignored, although we should check for simple things like # # gzip'd or compressed files. # ctype, encoding = mimetypes.guess_type(attachment) # if ctype is None or encoding is not None: # # No guess could be made, or the file is encoded (compressed), so # # use a generic bag-of-bits type. # ctype = 'application/octet-stream' # maintype, subtype = ctype.split('/', 1) # if maintype == 'text': # fp = open(attachment) # # Note: we should handle calculating the charset # part = MIMEText(fp.read(), _subtype=subtype) # fp.close() # elif maintype == 'image': # fp = open(attachment, 'rb') # part = MIMEImage(fp.read(), _subtype=subtype) # fp.close() # elif maintype == 'audio': # fp = open(attachment, 'rb') # part = MIMEAudio(fp.read(), _subtype=subtype) # fp.close() # else: # fp = open(attachment, 'rb') # part = MIMEBase(maintype, subtype) # part.set_payload(fp.read()) # fp.close() # # Encode the payload using Base64 # encoders.encode_base64(part) # # Set the filename parameter # part.add_header('Content-Disposition', 'attachment', filename=attachment) # message.attach(part) return self.ses.send_raw_email(self._source, message.as_string(), destinations=self._to_addresses)
def startup(self): self.connection = SESConnection(aws_access_key_id=self.id, aws_secret_access_key=self.key, host=self.host)