def send_mail(self, template_prefix, email, context): subject = render_to_string( '{0}_subject.txt'.format(template_prefix), context ) subject = " ".join(subject.splitlines()).strip() subject = self.format_email_subject(subject) # Allauth sends some additional data in the context, remove it if the # pieces can't be json encoded removed_keys = [] for key in list(context.keys()): try: _ = json.dumps(context[key]) # noqa for F841 except (ValueError, TypeError): removed_keys.append(key) del context[key] if removed_keys: log.debug('Removed context we were unable to serialize: %s', removed_keys) send_email( recipient=email, subject=subject, template='{0}_message.txt'.format(template_prefix), template_html='{0}_message.html'.format(template_prefix), context=context )
def email_notification(version, build, email): """Send email notifications for build failure :param version: :py:cls:`Version` instance that failed :param build: :py:cls:`Build` instance that failed :param email: Email recipient address """ log.debug(LOG_TEMPLATE.format(project=version.project.slug, version=version.slug, msg='sending email to: %s' % email)) context = {'version': version, 'project': version.project, 'build': build, 'build_url': 'https://{0}{1}'.format( getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org'), build.get_absolute_url()), 'unsub_url': 'https://{0}{1}'.format( getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org'), reverse('projects_notifications', args=[version.project.slug])), } if build.commit: title = _('Failed: {project.name} ({commit})').format(commit=build.commit[:8], **context) else: title = _('Failed: {project.name} ({version.verbose_name})').format(**context) send_email( email, title, template='projects/email/build_failed.txt', template_html='projects/email/build_failed.html', context=context )
def email_notification(version, build, email): """Send email notifications for build failure :param version: :py:class:`Version` instance that failed :param build: :py:class:`Build` instance that failed :param email: Email recipient address """ log.debug( LOG_TEMPLATE.format(project=version.project.slug, version=version.slug, msg="sending email to: %s" % email) ) context = { "version": version, "project": version.project, "build": build, "build_url": "https://{0}{1}".format( getattr(settings, "PRODUCTION_DOMAIN", "readthedocs.org"), build.get_absolute_url() ), "unsub_url": "https://{0}{1}".format( getattr(settings, "PRODUCTION_DOMAIN", "readthedocs.org"), reverse("projects_notifications", args=[version.project.slug]), ), } if build.commit: title = _("Failed: {project.name} ({commit})").format(commit=build.commit[:8], **context) else: title = _("Failed: {project.name} ({version.verbose_name})").format(**context) send_email( email, title, template="projects/email/build_failed.txt", template_html="projects/email/build_failed.html", context=context, )
def email_notification(version, build, email): """ Send email notifications for build failure. :param version: :py:class:`Version` instance that failed :param build: :py:class:`Build` instance that failed :param email: Email recipient address """ log.debug(LOG_TEMPLATE.format(project=version.project.slug, version=version.slug, msg='sending email to: %s' % email)) context = {'version': version, 'project': version.project, 'build': build, 'build_url': 'https://{0}{1}'.format( getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org'), build.get_absolute_url()), 'unsub_url': 'https://{0}{1}'.format( getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org'), reverse('projects_notifications', args=[version.project.slug])), } if build.commit: title = _('Failed: {project.name} ({commit})').format(commit=build.commit[:8], **context) else: title = _('Failed: {project.name} ({version.verbose_name})').format(**context) send_email( email, title, template='projects/email/build_failed.txt', template_html='projects/email/build_failed.html', context=context )
def form_valid(self, form): """If form is valid, send emails to selected recipients This treats the body field as a string template, so full template tags are allowed in the field. The object will be available in the template as the variable specified by the ``email_context_object_name`` class variable. """ count = 0 template = Template(form.cleaned_data['body']) for obj in self.get_queryset().all(): ctx = Context() if self.email_context_data is not None: ctx.update(self.email_context_data) ctx[self.email_context_object_name] = obj for recipient in self.get_object_recipients(obj): send_email( recipient.email, subject=form.cleaned_data['subject'], template='core/email/common.txt', template_html='core/email/common.html', context={'content': template.render(ctx)}, request=self.request, ) count += 1 if count == 0: self.message_user("No recipients to send to", level=messages.ERROR) else: self.message_user("Queued {0} messages".format(count)) return HttpResponseRedirect(self.request.get_full_path())
def email_notification(version, build, email): """ Send email notifications for build failure. :param version: :py:class:`Version` instance that failed :param build: :py:class:`Build` instance that failed :param email: Email recipient address """ log.debug( LOG_TEMPLATE.format( project=version.project.slug, version=version.slug, msg='sending email to: %s' % email, ), ) # We send only what we need from the Django model objects here to avoid # serialization problems in the ``readthedocs.core.tasks.send_email_task`` context = { 'version': { 'verbose_name': version.verbose_name, }, 'project': { 'name': version.project.name, }, 'build': { 'pk': build.pk, 'error': build.error, }, 'build_url': 'https://{}{}'.format( getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org'), build.get_absolute_url(), ), 'unsub_url': 'https://{}{}'.format( getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org'), reverse('projects_notifications', args=[version.project.slug]), ), } if build.commit: title = _( 'Failed: {project[name]} ({commit})', ).format(commit=build.commit[:8], **context) else: title = _('Failed: {project[name]} ({version[verbose_name]})').format( **context ) send_email( email, title, template='projects/email/build_failed.txt', template_html='projects/email/build_failed.html', context=context, )
def send(self, notification): if notification.level >= REQUIREMENT: send_email( recipient=notification.user.email, subject=notification.get_subject(), template='core/email/common.txt', template_html='core/email/common.html', context={ 'content': notification.render(self.name, source_format=HTML), }, request=self.request, )
def send_email(self, email): """Send email notifications for build failures.""" # We send only what we need from the Django model objects here to avoid # serialization problems in the ``readthedocs.core.tasks.send_email_task`` protocol = 'http' if settings.DEBUG else 'https' context = { 'version': { 'verbose_name': self.version.verbose_name, }, 'project': { 'name': self.project.name, }, 'build': { 'pk': self.build.pk, 'error': self.build.error, }, 'build_url': '{}://{}{}'.format( protocol, settings.PRODUCTION_DOMAIN, self.build.get_absolute_url(), ), 'unsubscribe_url': '{}://{}{}'.format( protocol, settings.PRODUCTION_DOMAIN, reverse('projects_notifications', args=[self.project.slug]), ), } if self.build.commit: title = _('Failed: {project[name]} ({commit})').format( commit=self.build.commit[:8], **context, ) else: title = _('Failed: {project[name]} ({version[verbose_name]})' ).format(**context) log.info( 'Sending email notification.', email=email, project_slug=self.project.slug, version_slug=self.version.slug, build_id=self.build.id, ) send_email( email, title, template='projects/email/build_failed.txt', template_html='projects/email/build_failed.html', context=context, )
def weekly_subscription_stats_email(recipients=None): """ Weekly email to communicate stats about subscriptions. :param list recipients: List of emails to send the stats to. """ if not recipients: log.info('No recipients to send stats to.') return last_week = timezone.now() - datetime.timedelta(weeks=1) yesterday = timezone.now() - datetime.timedelta(days=1) projects = Project.objects.filter(pub_date__gte=last_week).count() builds = Build.objects.filter(date__gte=last_week).count() organizations = Organization.objects.filter(pub_date__gte=last_week).count() domains = Domain.objects.filter(created__gte=last_week).count() organizations_to_disable = Organization.objects.disable_soon(days=30).count() users = User.objects.filter(date_joined__gte=last_week).count() subscriptions = ( Subscription.objects .filter( trial_end_date__gte=last_week, trial_end_date__lte=yesterday, ) .values('status', 'plan__name') .annotate(total_status=Count('status')) .order_by('status') ) context = { 'projects': projects, 'builds': builds, 'organizations': organizations, 'domains': domains, 'organizations_to_disable': organizations_to_disable, 'users': users, 'subscriptions': list(subscriptions), } log.info('Sending weekly subscription stats email.') send_email( from_email='Read the Docs <*****@*****.**>', subject='Weekly subscription stats', recipient=recipients[0], template='subscriptions/notifications/subscription_stats_email.txt', template_html=None, context=context, # Use ``cc`` here because our ``send_email`` does not accept a list of recipients cc=recipients[1:], )
def send_team_invite_email(invite, request): """Send an organization team invite email.""" log.info('Sending team invite.', team=invite.team, email=invite.email) send_email( invite.email, subject='Join your team at Read the Docs', template='organizations/email/team_invite.txt', template_html='organizations/email/team_invite.html', context={ 'invite_hash': invite.hash, 'sender_full_name': request.user.get_full_name(), 'sender_username': request.user.username, 'organization_name': invite.organization.name, }, request=request, )
def email_notification(version, build, email): """ Send email notifications for build failure. :param version: :py:class:`Version` instance that failed :param build: :py:class:`Build` instance that failed :param email: Email recipient address """ log.debug(LOG_TEMPLATE.format(project=version.project.slug, version=version.slug, msg='sending email to: %s' % email)) # We send only what we need from the Django model objects here to avoid # serialization problems in the ``readthedocs.core.tasks.send_email_task`` context = { 'version': { 'verbose_name': version.verbose_name, }, 'project': { 'name': version.project.name, }, 'build': { 'pk': build.pk, 'error': build.error, }, 'build_url': 'https://{0}{1}'.format( getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org'), build.get_absolute_url(), ), 'unsub_url': 'https://{0}{1}'.format( getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org'), reverse('projects_notifications', args=[version.project.slug]), ), } if build.commit: title = _('Failed: {project[name]} ({commit})').format(commit=build.commit[:8], **context) else: title = _('Failed: {project[name]} ({version[verbose_name]})').format(**context) send_email( email, title, template='projects/email/build_failed.txt', template_html='projects/email/build_failed.html', context=context, )
def form_valid(self, form): """If form is valid, send emails to selected users""" count = 0 for user in self.get_queryset().all(): send_email( user.email, subject=form.cleaned_data['subject'], template='core/email/common.txt', template_html='core/email/common.html', context={'user': user, 'content': form.cleaned_data['body']}, request=self.request, ) count += 1 if count == 0: self.message_user("No recipients to send to", level=messages.ERROR) else: self.message_user("Queued {0} messages".format(count)) return HttpResponseRedirect(self.request.get_full_path())
def send(self, notification): # FIXME: if the level is an ERROR an email is received and sometimes # it's not necessary. This behavior should be clearly documented in the # code if notification.level >= REQUIREMENT: send_email( recipient=notification.user.email, subject=notification.get_subject(), template='core/email/common.txt', template_html='core/email/common.html', context={ 'content': notification.render( self.name, source_format=HTML, ), }, request=self.request, )
def send_team_add_email(team_member, request): """Send an organization team add email.""" log.info( 'Sending team add notification.', team=team_member.team, email=team_member.member.email, ) send_email( team_member.member.email, subject='Join your team at Read the Docs', template='organizations/email/team_add.txt', template_html='organizations/email/team_add.html', context={ 'sender_full_name': request.user.get_full_name(), 'sender_username': request.user.username, 'organization_name': team_member.team.organization.name, 'organization_slug': team_member.team.organization.slug, }, request=request, )
def send(self, notification): if not notification.send_email: return # FIXME: if the level is an ERROR an email is received and sometimes # it's not necessary. This behavior should be clearly documented in the # code if notification.level >= REQUIREMENT: send_email( recipient=notification.user.email, subject=notification.get_subject(), template='core/email/common.txt', template_html='core/email/common.html', context={ 'content': notification.render( self.name, source_format=HTML, ), }, request=self.request, )
def form_valid(self, form): """If form is valid, send emails to selected users""" count = 0 for user in self.get_queryset().all(): send_email( user.email, subject=form.cleaned_data['subject'], template='core/email/common.txt', template_html='core/email/common.html', context={ 'user': user, 'content': form.cleaned_data['body'] }, request=self.request, ) count += 1 if count == 0: self.message_user("No receipients to send to", level=messages.ERROR) else: self.message_user("Queued {0} messages".format(count)) return HttpResponseRedirect(self.request.get_full_path())