import io import uuid import zipfile from datetime import datetime from django.conf import settings from django.core import mail from django.core.management.base import BaseCommand from django.utils import timezone from main import models, util def get_mail_connection(): """Returns the default EmailBackend but instantiated with a custom host.""" return mail.get_connection( "django.core.mail.backends.smtp.EmailBackend", host=settings.EMAIL_HOST_BROADCASTS, ) def get_unsubscribe_url(user): return util.get_protocol() + user.get_export_unsubscribe_url() def get_email_body(user): """ Returns the email body (which contains the post body) for the automated export email. """ today = datetime.now().date().strftime("%B %d, %Y") body = f"""Greetings, This is the {today} edition of your Mataroa blog export. Please find your blog’s zip archive in markdown format attached. --- Stop receiving exports: {get_unsubscribe_url(user)} """ return body class Command(BaseCommand): help = "Generate zip account exports and email them to users." def handle(self, *args, **options): if timezone.now().day != 1: msg = "No action. Not the first day of the month." self.stdout.write(self.style.NOTICE(msg)) return self.stdout.write(self.style.NOTICE("Processing email exports.")) # gather all user posts for all users users = models.User.objects.filter(mail_export_on=True) for user in users: self.stdout.write(self.style.NOTICE(f"Processing user {user.username}.")) user_posts = models.Post.objects.filter(owner=user) export_posts = [] for p in user_posts: pub_date = p.published_at or p.created_at title = p.slug + ".md" body = ( f"# {p.title}\n\n" f"> Published on {pub_date.strftime('%b %-d, %Y')}\n\n" f"{p.body}\n" ) export_posts.append((title, io.BytesIO(body.encode()))) # write zip archive in /tmp/ export_name = "export-markdown-" + str(uuid.uuid4())[:8] container_dir = f"{user.username}-mataroa-blog" zip_outfile = f"/tmp/{export_name}.zip" with zipfile.ZipFile( zip_outfile, "a", zipfile.ZIP_DEFLATED, False ) as export_archive: for file_name, data in export_posts: export_archive.writestr( export_name + f"/{container_dir}/" + file_name, data.getvalue() ) # reopen zipfile and load in memory with open(zip_outfile, "rb") as f: # create emails today = datetime.now().date().isoformat() email = mail.EmailMessage( subject=f"Mataroa export {today} — {user.username}.{settings.CANONICAL_HOST}", body=get_email_body(user), from_email=settings.DEFAULT_FROM_EMAIL, to=[user.email], headers={ "X-PM-Message-Stream": "exports", # postmark-specific header "List-Unsubscribe": get_unsubscribe_url(user), "List-Unsubscribe-Post": "List-Unsubscribe=One-Click", }, attachments=[(f"{export_name}.zip", f.read(), "application/zip")], ) # sent out messages connection = get_mail_connection() connection.send_messages([email]) self.stdout.write(self.style.SUCCESS(f"Export sent to {user.username}.")) # log export record name = f"{export_name}.zip" record = models.ExportRecord.objects.create(name=name, user=user) self.stdout.write( self.style.SUCCESS(f"Logging export record for '{record.name}'.") ) # log all users mailing is complete self.stdout.write(self.style.SUCCESS("Emailing all exports complete."))