# Society Self-Service # Copyright © 2018-2019 Yingtong Li (RunasSudo) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import boto3 from botocore.exceptions import ClientError import premailer from django.core.management.base import BaseCommand, CommandError from django.conf import settings from django.template import loader from django.urls import reverse from ssmembership.monboard import get_members, set_emailed_by_email import hmac import logging import time import urllib.parse class Command(BaseCommand): help = 'Send emails for membership onboarding' def add_arguments(self, parser): parser.add_argument('ids', nargs='*', type=int, help='Members with ID numbers equal to these values will be emailed (default all)') parser.add_argument('--render', action='store_true', help='Render to stdout instead of sending emails') def handle(self, *args, **options): template_html = loader.get_template('ssmembership/email/onboard.html') template_txt = loader.get_template('ssmembership/email/onboard.txt') members = get_members() if len(options['ids']) > 0: members = [member for member in members if member[0] in options['ids']] else: raise Exception('Must provide IDs') client = boto3.client('ses', aws_access_key_id=settings.AWS_KEY_ID, aws_secret_access_key=settings.AWS_SECRET, region_name=settings.AWS_REGION) def send_mail(**kwargs): for i in range(0, 10): try: client.send_email(**kwargs) return except ClientError as e: if e['Error']['Code'] == 'Throttling' and e['Error']['Message'] == 'Maximum sending rate exceeded.': wait_time = max(10*(2**i), 5000) self.stdout.write(self.style.NOTICE('Reached maximum sending rate, waiting {} ms'.format(wait_time))) time.sleep(wait_time/1000) else: raise e raise Exception('Reached maximum number of retries') for member in members: #_id, student_id, email, first_name, last_name, year, is_msa, phone, date, purchased, imported, emailed if member[10] or member[11]: continue sig = hmac.new(settings.SECRET_KEY_MEMBERSIG.encode('utf-8'), member[2].encode('utf-8'), 'sha256').hexdigest() renew_url = reverse('monboard_signed') + '?' + urllib.parse.urlencode({'email': member[2], 'sig': sig}) template_args = { 'name': member[3].strip() + ' ' + member[4].strip(), 'renew_url': renew_url, 'baseurl': 'https://' + settings.ALLOWED_HOSTS[0], 'purchased': member[10] } content_html = premailer.Premailer(template_html.render(template_args), cssutils_logging_level=logging.ERROR).transform() content_txt = template_txt.render(template_args) if options['render']: self.stdout.write('Content-Type: multipart/alternative; boundary=boundary\n\n--boundary\nContent-Type: text/html; charset=utf-8\n\n' + content_html + '\n--boundary\nContent-Type: text/plain; charset=utf-8\n\n' + content_txt + '\n--boundary') else: self.stdout.write('Emailing {} at {}'.format(member[0], member[2])) send_mail( Destination={ 'ToAddresses': [member[2]], }, Message={ 'Body': { 'Html': { 'Charset': 'utf-8', 'Data': content_html, }, 'Text': { 'Charset': 'utf-8', 'Data': content_txt, }, }, 'Subject': { 'Charset': 'utf-8', 'Data': 'Activate your ' + settings.ORG_NAME + ' membership', }, }, Source='{} <{}>'.format(settings.ORG_NAME, settings.AWS_SENDER_EMAIL), ) set_emailed_by_email(member[2])