Ejemplo n.º 1
0
def message_notification_email(data):
    """Queues a system email for a new message notification."""
    from r2.lib.pages import MessageNotificationEmail

    MAX_EMAILS_PER_DAY = 1000
    MESSAGE_THROTTLE_KEY = 'message_notification_emails'

    # If our counter's expired, initialize it again.
    g.cache.add(MESSAGE_THROTTLE_KEY, 0, time=24 * 60 * 60)

    for datum in data.itervalues():
        datum = json.loads(datum)
        user = Account._byID36(datum['to'], data=True)
        comment = Comment._by_fullname(datum['comment'], data=True)

        # In case a user has enabled the preference while it was enabled for
        # them, but we've since turned it off.  We need to explicitly state the
        # user because we're not in the context of an HTTP request from them.
        if not feature.is_enabled('orangereds_as_emails', user=user):
            continue

        if g.cache.get(MESSAGE_THROTTLE_KEY) > MAX_EMAILS_PER_DAY:
            raise Exception(
                'Message notification emails: safety limit exceeded!')

        mac = generate_notification_email_unsubscribe_token(
            datum['to'],
            user_email=user.email,
            user_password_hash=user.password)
        base = g.https_endpoint or g.origin
        unsubscribe_link = base + '/mail/unsubscribe/%s/%s' % (datum['to'],
                                                               mac)

        templateData = {
            'sender_username': datum.get('from', ''),
            'comment': comment,
            'permalink': datum['permalink'],
            'unsubscribe_link': unsubscribe_link,
        }
        _system_email(
            user.email,
            MessageNotificationEmail(**templateData).render(style='email'),
            Email.Kind.MESSAGE_NOTIFICATION,
            from_address=g.notification_email)

        g.stats.simple_event('email.message_notification.queued')
        g.cache.incr(MESSAGE_THROTTLE_KEY)
Ejemplo n.º 2
0
def message_notification_email(data):
    """Queues a system email for a new message notification."""
    from r2.lib.pages import MessageNotificationEmail

    timer_start = time.time()

    MAX_EMAILS_PER_USER = 30
    MAX_MESSAGES_PER_BATCH = 5
    total_messages_sent = 0
    inbox_item_lookup_count = 0

    unique_user_list = make_message_dict_unique(data)
    g.log.info("there are %s users for this batch of emails" %
               len(unique_user_list))

    for datum in unique_user_list.itervalues():
        user = Account._byID36(datum['to'], data=True)
        g.log.info('user fullname: %s' % user._fullname)

        # In case a user has enabled the preference while it was enabled for
        # them, but we've since turned it off.  We need to explicitly state the
        # user because we're not in the context of an HTTP request from them.
        if not feature.is_enabled('orangereds_as_emails', user=user):
            g.log.info('feature not enabled for user: %s' % user._fullname)
            continue

        # Don't send more than MAX_EMAILS_PER_USER per user per day
        user_notification_ratelimit = SimpleRateLimit(
            name="email_message_notification_%s" % user._id36,
            seconds=int(datetime.timedelta(days=1).total_seconds()),
            limit=MAX_EMAILS_PER_USER,
        )
        if not user_notification_ratelimit.check():
            g.log.info('message blocked at user_notification_ratelimit: %s' %
                       user_notification_ratelimit)
            continue

        # Get all new messages that haven't been emailed
        inbox_items = get_unread_and_unemailed(user)
        inbox_item_lookup_count += 1

        if not inbox_items:
            g.log.info('no inbox items found for %s' % user._fullname)
            continue

        newest_inbox_rel = inbox_items[-1][0]
        oldest_inbox_rel = inbox_items[0][0]

        now = datetime.datetime.now(g.tz)
        start_date = datetime.datetime.strptime(
            datum['start_date'], "%Y-%m-%d %H:%M:%S").replace(tzinfo=g.tz)

        # If messages are still being queued within the cooling period or
        # messages have been queued past the max delay, then keep waiting
        # a little longer to batch all of the messages up
        if (start_date != newest_inbox_rel._date and now <
                newest_inbox_rel._date + NOTIFICATION_EMAIL_COOLING_PERIOD and
                now < oldest_inbox_rel._date + NOTIFICATION_EMAIL_MAX_DELAY):
            g.log.info('messages still being batched for: %s' % user._fullname)
            continue

        messages = []
        message_count = 0
        more_unread_messages = False
        non_preview_usernames = set()

        # Batch messages to email starting with older messages
        for inbox_rel, message in inbox_items:
            # Get sender_name, replacing with display_author if it exists
            g.log.info('user fullname: %s, message fullname: %s' %
                       (user._fullname, message._fullname))

            sender_name = get_sender_name(message)

            if message_count >= MAX_MESSAGES_PER_BATCH:
                # prevent duplicate usernames for template display
                non_preview_usernames.add(sender_name)
                more_unread_messages = True
            else:
                link = None
                parent = None
                if isinstance(message, Comment):
                    permalink = message.make_permalink_slow(context=1,
                                                            force_domain=True)
                    if message.parent_id:
                        parent = Comment._byID(message.parent_id, data=True)
                    else:
                        link = Link._byID(message.link_id, data=True)
                else:
                    permalink = message.make_permalink(force_domain=True)

                message_type = get_message_type(message, parent, user, link)

                messages.append({
                    "author_name": sender_name,
                    "message_type": message_type,
                    "body": message.body,
                    "date": long_datetime(message._date),
                    "permalink": permalink,
                    "id": message._id,
                    "fullname": message._fullname,
                    "subject": getattr(message, 'subject', ''),
                })

            inbox_rel.emailed = True
            inbox_rel._commit()
            message_count += 1

        mac = generate_notification_email_unsubscribe_token(
            datum['to'],
            user_email=user.email,
            user_password_hash=user.password)
        base = g.https_endpoint or g.origin
        unsubscribe_link = base + '/mail/unsubscribe/%s/%s' % (datum['to'],
                                                               mac)
        inbox_url = base + '/message/inbox'

        # unique email_hash for emails, to be used in utm tags
        id_str = ''.join(str(message['id'] for message in messages))
        email_hash = hashlib.sha1(id_str).hexdigest()

        base_utm_query = {
            'utm_name': email_hash,
            'utm_source': 'email',
            'utm_medium': 'message_notification',
        }

        non_preview_usernames_str = generate_non_preview_usernames_str(
            non_preview_usernames)

        templateData = {
            'messages': messages,
            'unsubscribe_link': unsubscribe_link,
            'more_unread_messages': more_unread_messages,
            'message_count': message_count,
            'max_message_display_count': MAX_MESSAGES_PER_BATCH,
            'non_preview_usernames_str': non_preview_usernames_str,
            'base_url': base,
            'base_utm_query': base_utm_query,
            'inbox_url': inbox_url,
        }
        custom_headers = {'List-Unsubscribe': "<%s>" % unsubscribe_link}
        g.log.info('sending message for user: %s' % user._fullname)
        g.email_provider.send_email(
            to_address=user.email,
            from_address="Reddit <%s>" % g.notification_email,
            subject=Email.subjects[Email.Kind.MESSAGE_NOTIFICATION],
            text=MessageNotificationEmail(**templateData).render(
                style='email'),
            html=MessageNotificationEmail(**templateData).render(style='html'),
            custom_headers=custom_headers,
            email_type='message_notification_email',
        )

        total_messages_sent += 1

        # report the email event to data pipeline
        g.events.orangered_email_event(
            request=request,
            context=c,
            user=user,
            messages=messages,
            email_hash=email_hash,
            reply_count=message_count,
            newest_reply_age=newest_inbox_rel._date,
            oldest_reply_age=oldest_inbox_rel._date,
        )

        g.stats.simple_event('email.message_notification.queued')
        user_notification_ratelimit.record_usage()

    timer_end = time.time()
    g.log.info("Took %s seconds to send orangered emails" %
               (timer_end - timer_start))

    g.log.info("Total number of messages sent: %s" % total_messages_sent)
    g.log.info("Total count of inbox lookups: %s" % inbox_item_lookup_count)