def test_bounce_over_limit(self):
        """
        Tests that all the user's subscriptions are dropped when too many
        bounces are received.
        """
        # Set up some prior bounces - one each day.
        date = timezone.now().date()
        for days in range(1, settings.PTS_MAX_DAYS_TOLERATE_BOUNCE):
            self.add_sent(self.user, date - timedelta(days=days))
            self.add_bounce(self.user, date - timedelta(days=days))
        # Set up a sent mail today.
        self.add_sent(self.user, date)
        # Make sure there were at least some subscriptions
        packages_subscribed_to = [
            subscription.package.name
            for subscription in self.user.subscription_set.all()
        ]
        self.assertTrue(len(packages_subscribed_to) > 0)

        # Receive a bounce message.
        self.run_dispatch(self.create_bounce_address(self.user.email))

        # Assert that the user's subscriptions have been dropped.
        self.assertEqual(self.user.subscription_set.count(), 0)
        # A notification was sent to the user.
        self.assertEqual(len(mail.outbox), 1)
        self.assertIn(self.user.email, mail.outbox[0].to)
        # Check that the content of the email is correct.
        self.assertEqual(mail.outbox[0].body, pts_render_to_string(
            'dispatch/unsubscribed-due-to-bounces-email.txt', {
                'email': self.user.email,
                'packages': packages_subscribed_to
            }
        ))
 def handle(self):
     self.reply(pts_render_to_string('control/help.txt', {
         'descriptions': [
             command.META.get('description', '')
             for command in UNIQUE_COMMANDS
         ],
     }))
Exemple #3
0
 def get_confirmation_message(self):
     """
     :returns: A message giving additional information about unsubscribing
         from all packages.
     :rtype: string
     """
     return pts_render_to_string(
         'control/email-unsubscribeall-confirmation.txt'
     )
Exemple #4
0
 def get_confirmation_message(self):
     """
     :returns: A message giving additional information about subscribing to
         a package.
     :rtype: string
     """
     return pts_render_to_string(
         'control/email-subscription-confirmation.txt', {
             'package': self.package,
         }
     )
def handle_bounces(sent_to_address):
    """
    Handles a received bounce message.

    :param sent_to_address: The envelope-to (return path) address to which the
        bounced email was returned.
    :type sent_to_address: string
    """
    bounce_email, user_email = verp.decode(sent_to_address)
    match = re.match(r"^bounces\+(\d{8})@" + PTS_FQDN, bounce_email)
    if not match:
        # Invalid bounce address
        logger.error("Invalid bounce address " + bounce_email)
        return
    try:
        date = datetime.strptime(match.group(1), "%Y%m%d")
    except ValueError:
        # Invalid bounce address
        logger.error("Invalid bounce address " + bounce_email)
        return
    EmailUserBounceStats.objects.add_bounce_for_user(email=user_email, date=date)

    logger.info("Logged bounce for {email} on {date}".format(email=user_email, date=date))
    user = EmailUserBounceStats.objects.get(user_email__email=user_email)
    if user.has_too_many_bounces():
        logger.info("{email} has too many bounces".format(email=user_email))

        email_body = pts_render_to_string(
            "dispatch/unsubscribed-due-to-bounces-email.txt",
            {"email": user_email, "packages": user.packagename_set.all()},
        )
        EmailMessage(
            subject="All your subscriptions from the PTS have been cancelled",
            from_email=settings.PTS_BOUNCES_LIKELY_SPAM_EMAIL,
            to=[user_email],
            cc=[settings.PTS_CONTACT_EMAIL],
            body=email_body,
            headers={"From": settings.PTS_CONTACT_EMAIL},
        ).send()

        user.unsubscribe_all()
Exemple #6
0
    def post(self, request, slug):
        self.team = get_object_or_404(Team, slug=slug)
        if self.team.owner != request.user:
            raise PermissionDenied

        form = AddTeamMemberForm(request.POST)
        if form.is_valid():
            email = form.cleaned_data['email']
            # Emails that do not exist should be created
            user, _ = EmailUser.objects.get_or_create(email=email)
            # The membership is muted by default until the user confirms it
            membership = self.team.add_members([user], muted=True)[0]
            confirmation = MembershipConfirmation.objects.create_confirmation(
                membership=membership)
            send_mail(
                'PTS Team Membership Confirmation',
                pts_render_to_string('core/email-team-membership-confirmation.txt', {
                    'confirmation': confirmation,
                    'team': self.team,
                }),
                from_email=settings.PTS_CONTACT_EMAIL,
                recipient_list=[email])

        return redirect('pts-team-manage', slug=self.team.slug)
    def _ask_confirmation(self, email, commands, messages):
        """
        Sends a confirmation mail to a single user. Includes all commands that
        the user needs to confirm.
        """
        command_confirmation = CommandConfirmation.objects.create_for_commands(
            commands=commands)
        message = pts_render_to_string(
            'control/email-confirmation-required.txt', {
                'command_confirmation': command_confirmation,
                'confirmation_messages': self.confirmation_messages[email],
            }
        )
        subject = 'CONFIRM ' + command_confirmation.confirmation_key

        EmailMessage(
            subject=subject,
            to=[email],
            from_email=PTS_BOUNCES_EMAIL,
            headers={
                'From': PTS_CONTROL_EMAIL,
            },
            body=message,
        ).send()
Exemple #8
0
 def get_confirmation_email_content(self, confirmation):
     return pts_render_to_string(self.confirmation_email_template, {
         'confirmation': confirmation,
     })