def send_events_list(user, event_list, location): profile_url = urlresolvers.reverse('user_detail', args=(user.username, )) footer = 'You are receiving this email because your preferences for event reminders are on. To turn them off, visit %s' % profile_url sender = location.from_email() subject = '[' + location.email_subject_prefix + ']' + ' Reminder of your events today' current_tz = timezone.get_current_timezone() today_local = timezone.now().astimezone(current_tz).date() day_of_week = weekday_number_to_name[today_local.weekday()] plaintext = get_template('emails/events_today.txt') domain = Site.objects.get_current().domain c = { 'user': user, 'events': event_list, 'location_name': location.name, 'location': location, 'domain': domain, "footer": footer, "day_of_week": day_of_week } text_content = plaintext.render(c) mailgun_data = { "from": sender, "to": user.email, "subject": subject, "text": text_content, } return mailgun_send(mailgun_data)
def goodbye_email(use): ''' Send guest a departure email''' # this is split out by location because each location has a timezone that affects the value of 'today' domain = Site.objects.get_current().domain location = use.location c = { 'first_name': use.user.first_name, 'location': use.location, 'booking_url' : "https://" + domain + urlresolvers.reverse('booking_detail', args=(location.slug, use.booking.id,)), 'new_booking_url' : "https://" + domain + urlresolvers.reverse('location_stay', args=(location.slug,)), } text_content, html_content = render_templates(c, location, LocationEmailTemplate.DEPARTURE) subject = "[%s] Thank you for staying with us" % location.email_subject_prefix mailgun_data = { "from": use.location.from_email(), "to": [use.user.email], "subject": subject, "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def send_announce(request, user, location): from_address = location.from_email() subject = request.POST.get('subject') body_plain = request.POST.get('body-plain') body_html = request.POST.get('body-html') # Include attachements attachments = [] for attachment in request.FILES.values(): attachments.append(("attachment", attachment)) prefix = "[" + location.email_subject_prefix + "] " subject = prefix + subject logger.debug("subject: %s" % subject) # add in footer text_footer = '''\n\n-------------------------------------------\n*~*~*~* %s Announce *~*~*~* ''' % location.name body_plain = body_plain + text_footer if body_html: html_footer = '''<br><br>-------------------------------------------<br>*~*~*~* %s Announce *~*~*~* ''' % location.name body_html = body_html + html_footer # send the message mailgun_data = { "from": from_address, "to": [ user.email, ], "subject": subject, "text": body_plain, "html": body_html, } return mailgun_send(mailgun_data, attachments)
def goodbye_email(use): ''' Send guest a departure email''' # this is split out by location because each location has a timezone that affects the value of 'today' domain = Site.objects.get_current().domain location = use.location c = { 'first_name': use.user.first_name, 'location': use.location, 'booking_url': "https://" + domain + urlresolvers.reverse('booking_detail', args=( location.slug, use.booking.id, )), 'new_booking_url': "https://" + domain + urlresolvers.reverse('location_stay', args=(location.slug, )), } text_content, html_content = render_templates( c, location, LocationEmailTemplate.DEPARTURE) subject = "[%s] Thank you for staying with us" % location.email_subject_prefix mailgun_data = { "from": use.location.from_email(), "to": [use.user.email], "subject": subject, "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def send_announce(request, user, location): from_address = location.from_email() subject = request.POST.get('subject') body_plain = request.POST.get('body-plain') body_html = request.POST.get('body-html') # Include attachements attachments = [] for attachment in request.FILES.values(): attachments.append(("attachment", attachment)) prefix = "["+location.email_subject_prefix + "] " subject = prefix + subject logger.debug("subject: %s" % subject) # add in footer text_footer = '''\n\n-------------------------------------------\n*~*~*~* %s Announce *~*~*~* '''% location.name body_plain = body_plain + text_footer if body_html: html_footer = '''<br><br>-------------------------------------------<br>*~*~*~* %s Announce *~*~*~* '''% location.name body_html = body_html + html_footer # send the message mailgun_data = { "from": from_address, "to": [user.email, ], "subject": subject, "text": body_plain, "html": body_html, } return mailgun_send(mailgun_data, attachments)
def guests_residents_daily_update(location): # this is split out by location because each location has a timezone that affects the value of 'today' today = timezone.localtime(timezone.now()) arriving_today = Use.objects.filter(location=location).filter( arrive=today).filter(status='confirmed') departing_today = Use.objects.filter(location=location).filter( depart=today).filter(status='confirmed') events_today = published_events_today_local(location=location) if not arriving_today and not departing_today and not events_today: logger.debug("Nothing happening today at %s, skipping daily email" % location.name) return subject = "[%s] Events, Arrivals and Departures for %s" % ( location.email_subject_prefix, str(today.date())) admin_emails = [] for admin in location.house_admins.all(): if not admin.email in admin_emails: admin_emails.append(admin.email) to_emails = [] for r in Use.objects.confirmed_on_date(today, location): if (not r.user.email in admin_emails) and (not r.user.email in to_emails): to_emails.append(r.user.email) # Add all the non-admin residents at this location (admins get a different # email) for r in location.residents(): if (not r.email in admin_emails) and (not r.email in to_emails): to_emails.append(r.email) if len(to_emails) == 0: logger.debug("No non-admins to send daily update to") return None c = { 'today': today, 'domain': Site.objects.get_current().domain, 'location': location, 'arriving': arriving_today, 'departing': departing_today, 'events_today': events_today, } text_content, html_content = render_templates( c, location, LocationEmailTemplate.GUEST_DAILY) mailgun_data = { "from": location.from_email(), "to": to_emails, "subject": subject, "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def admin_daily_update(location): # this is split out by location because each location has a timezone that affects the value of 'today' today = timezone.localtime(timezone.now()).date() arriving_today = Use.objects.filter(location=location).filter(arrive=today).filter(status='confirmed') maybe_arriving_today = Use.objects.filter(location=location).filter(arrive=today).filter(status='approved') pending_now = Use.objects.filter(location=location).filter(status='pending') approved_now = Use.objects.filter(location=location).filter(status='approved') departing_today = Use.objects.filter(location=location).filter(depart=today).filter(status='confirmed') events_today = published_events_today_local(location=location) pending_or_feedback = events_pending(location=location) # if there are subscriptions ready for billing, the bills should have been # generated by another task. this is for notification purposes only so the # admins know the check 'em out. subscriptions_ready = Subscription.objects.ready_for_billing(location, target_date=today) if not arriving_today and not departing_today and not events_today and not maybe_arriving_today and not pending_now and not approved_now and not subscriptions_ready: logger.debug("Nothing happening today at %s, skipping daily email" % location.name) return subject = "[%s] %s Events and Guests" % (location.email_subject_prefix, today) admins_emails = [] for admin in location.house_admins.all(): if not admin.email in admins_emails: admins_emails.append(admin.email) if len(admins_emails) == 0: logger.debug('%s: No admins to send to' % location.slug) return None c = { 'today': today, 'domain': Site.objects.get_current().domain, 'location': location, 'arriving': arriving_today, 'maybe_arriving': maybe_arriving_today, 'pending_now': pending_now, 'approved_now': approved_now, 'departing': departing_today, 'events_today': events_today, 'events_pending': pending_or_feedback['pending'], 'events_feedback': pending_or_feedback['feedback'], 'subscriptions_ready': subscriptions_ready, } text_content, html_content = render_templates(c, location, LocationEmailTemplate.ADMIN_DAILY) mailgun_data = { "from": location.from_email(), "to": admins_emails, "subject": subject, "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def send_from_location_address(subject, text_content, html_content, recipient, location): ''' a somewhat generic send function using mailgun that sends plaintext from the location's generic stay@ address.''' mailgun_data={"from": location.from_email(), "to": [recipient, ], "subject": subject, "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def guests_residents_daily_update(location): # this is split out by location because each location has a timezone that affects the value of 'today' today = timezone.localtime(timezone.now()) arriving_today = Use.objects.filter(location=location).filter(arrive=today).filter(status='confirmed') departing_today = Use.objects.filter(location=location).filter(depart=today).filter(status='confirmed') events_today = published_events_today_local(location=location) if not arriving_today and not departing_today and not events_today: logger.debug("Nothing happening today at %s, skipping daily email" % location.name) return subject = "[%s] Events, Arrivals and Departures for %s" % (location.email_subject_prefix, str(today.date())) admin_emails = [] for admin in location.house_admins.all(): if not admin.email in admin_emails: admin_emails.append(admin.email) to_emails = [] for r in Use.objects.confirmed_on_date(today, location): if (not r.user.email in admin_emails) and (not r.user.email in to_emails): to_emails.append(r.user.email) # Add all the non-admin residents at this location (admins get a different # email) for r in location.residents(): if (not r.email in admin_emails) and (not r.email in to_emails): to_emails.append(r.email) if len(to_emails) == 0: logger.debug("No non-admins to send daily update to") return None c = { 'today': today, 'domain': Site.objects.get_current().domain, 'location': location, 'arriving' : arriving_today, 'departing' : departing_today, 'events_today': events_today, } text_content, html_content = render_templates(c, location, LocationEmailTemplate.GUEST_DAILY) mailgun_data = { "from": location.from_email(), "to": to_emails, "subject": subject, "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def send_from_location_address(subject, text_content, html_content, recipient, location): ''' a somewhat generic send function using mailgun that sends plaintext from the location's generic stay@ address.''' mailgun_data = { "from": location.from_email(), "to": [ recipient, ], "subject": subject, "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def updated_booking_notify(booking): domain = Site.objects.get_current().domain admin_path = urlresolvers.reverse('booking_manage', args=(booking.use.location.slug, booking.id,)) text_content = '''Howdy,\n\nA booking has been updated and requires your review.\n\nManage this booking at %s%s.''' % (domain, admin_path) recipients = [] for admin in booking.use.location.house_admins.all(): if not admin.email in recipients: recipients.append(admin.email) subject = "[%s] Booking Updated, %s %s, %s - %s" % (booking.use.location.email_subject_prefix, booking.use.user.first_name, booking.use.user.last_name, str(booking.use.arrive), str(booking.use.depart)) mailgun_data={"from": booking.use.location.from_email(), "to": recipients, "subject": subject, "text": text_content, } return mailgun_send(mailgun_data)
def weekly_reminder_email(user, event_list, location): profile_url = urlresolvers.reverse('user_detail', args=(user.username, )) location_name = location.name current_tz = timezone.get_current_timezone() today_local = timezone.now().astimezone(current_tz).date() tomorrow_local = today_local + datetime.timedelta(days=1) week_name = tomorrow_local.strftime("%B %d, %Y") footer = 'You are receiving this email because you requested weekly updates of upcoming events from %s. To turn them off, visit %s' % ( location_name, profile_url) sender = location.from_email() subject = '[' + location.email_subject_prefix + ']' + ' Upcoming events for the week of %s' % week_name current_tz = timezone.get_current_timezone() today_local = timezone.now().astimezone(current_tz).date() plaintext = get_template('emails/events_this_week.txt') htmltext = get_template('emails/events_this_week.html') domain = Site.objects.get_current().domain c_text = { 'user': user, 'events': event_list, 'location_name': location_name, 'location': location, 'domain': domain, "footer": footer, "week_name": week_name } text_content = plaintext.render(c_text) c_html = { 'user': user, 'events': event_list, 'location_name': location_name, 'location': location, 'domain': domain, "footer": footer, "week_name": week_name } html_content = htmltext.render(c_html) mailgun_data = { "from": sender, "to": user.email, "subject": subject, "text": text_content, "html": html_content, } return mailgun_send(mailgun_data)
def weekly_reminder_email(user, event_list, location): profile_url = urlresolvers.reverse('user_detail', args=(user.username, )) location_name = location.name current_tz = timezone.get_current_timezone() today_local = timezone.now().astimezone(current_tz).date() tomorrow_local = today_local + datetime.timedelta(days=1) week_name = tomorrow_local.strftime("%B %d, %Y") footer = 'You are receiving this email because you requested weekly updates of upcoming events from %s. To turn them off, visit %s' % (location_name, profile_url) sender = location.from_email() subject = '[' + location.email_subject_prefix + ']' + ' Upcoming events for the week of %s' % week_name current_tz = timezone.get_current_timezone() today_local = timezone.now().astimezone(current_tz).date() plaintext = get_template('emails/events_this_week.txt') htmltext = get_template('emails/events_this_week.html') domain = Site.objects.get_current().domain c_text = { 'user': user, 'events': event_list, 'location_name': location_name, 'location': location, 'domain': domain, "footer": footer, "week_name": week_name } text_content = plaintext.render(c_text) c_html = { 'user': user, 'events': event_list, 'location_name': location_name, 'location': location, 'domain': domain, "footer": footer, "week_name": week_name } html_content = htmltext.render(c_html) mailgun_data = { "from": sender, "to": user.email, "subject": subject, "text": text_content, "html": html_content, } return mailgun_send(mailgun_data)
def admin_new_subscription_notify(subscription): domain = Site.objects.get_current().domain admin_path = urlresolvers.reverse('subscription_manage_detail', args=(subscription.location.slug, subscription.id,)) text_content = '''Howdy,\n\nA new subscription for %s %s has been added for %d/mo starting %s.\n\nManage this subscription at %s%s.''' % ( subscription.user.first_name , subscription.user.last_name, subscription.price, str(subscription.start_date), domain, admin_path ) recipients = [] for admin in subscription.location.house_admins.all(): if not admin.email in recipients: recipients.append(admin.email) subject = "[%s] Subscription Added for %s %s" % (subscription.location.email_subject_prefix, subscription.user.first_name, subscription.user.last_name) mailgun_data={"from": subscription.location.from_email(), "to": recipients, "subject": subject, "text": text_content, } return mailgun_send(mailgun_data)
def event_approved_notification(event, location): ''' send an email to organizers letting them know their event has been approved.''' logger.debug("event_approved_notification") recipients = [organizer.email for organizer in event.organizers.all()] subject = '[' + location.email_subject_prefix + ']' + " Your event is ready to be published" from_address = location.from_email() plaintext = get_template('emails/event_approved_notify.txt') c = { 'event': event, 'domain': Site.objects.get_current().domain, 'location': location, } body_plain = plaintext.render(c) mailgun_data = { "from": from_address, "to": recipients, "subject": subject, "text": body_plain, } return mailgun_send(mailgun_data)
def new_event_notification(event, location): # notify the event admins that a new event has been proposed admin_group = event.admin recipients = [admin.email for admin in admin_group.users.all()] event_short_title = event.title[0:50] if len(event.title) > 50: event_short_title = event_short_title + "..." subject = '[' + location.email_subject_prefix + ']' + " A new event has been created: %s" % event_short_title from_address = location.from_email() plaintext = get_template('emails/new_event_notify.txt') c = { 'event': event, 'location': location, 'domain': Site.objects.get_current().domain, } body_plain = plaintext.render(c) mailgun_data = { "from": from_address, "to": recipients, "subject": subject, "text": body_plain, } return mailgun_send(mailgun_data)
def guest_welcome(use): ''' Send guest a welcome email''' # this is split out by location because each location has a timezone that affects the value of 'today' domain = Site.objects.get_current().domain location = use.location intersecting_uses = Use.objects.filter(arrive__gte=use.arrive).filter(depart__lte=use.depart) residents = location.residents() intersecting_events = Event.objects.filter(location=location).filter(start__gte=use.arrive).filter(end__lte=use.depart) profiles = None day_of_week = weekday_number_to_name[use.arrive.weekday()] c = { 'first_name': use.user.first_name, 'day_of_week' : day_of_week, 'location': use.location, 'use': use, 'current_email' : 'current@%s.mail.embassynetwork.com' % location.slug, 'site_url': "https://" + domain + urlresolvers.reverse('location_detail', args=(location.slug,)), 'events_url' : "https://" + domain + urlresolvers.reverse('gather_upcoming_events', args=(location.slug,)), 'profile_url' : "https://" + domain + urlresolvers.reverse('user_detail', args=(use.user.username,)), 'booking_url' : "https://" + domain + urlresolvers.reverse('booking_detail', args=(location.slug, use.booking.id,)), 'intersecting_bookings': intersecting_uses, 'intersecting_events': intersecting_events, 'residents': residents, } text_content, html_content = render_templates(c, location, LocationEmailTemplate.WELCOME) mailgun_data = { "from": use.location.from_email(), "to": [use.user.email], "subject": "[%s] See you on %s" % (use.location.email_subject_prefix, day_of_week), "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def updated_booking_notify(booking): domain = Site.objects.get_current().domain admin_path = urlresolvers.reverse('booking_manage', args=( booking.use.location.slug, booking.id, )) text_content = '''Howdy,\n\nA booking has been updated and requires your review.\n\nManage this booking at %s%s.''' % ( domain, admin_path) recipients = [] for admin in booking.use.location.house_admins.all(): if not admin.email in recipients: recipients.append(admin.email) subject = "[%s] Booking Updated, %s %s, %s - %s" % ( booking.use.location.email_subject_prefix, booking.use.user.first_name, booking.use.user.last_name, str( booking.use.arrive), str(booking.use.depart)) mailgun_data = { "from": booking.use.location.from_email(), "to": recipients, "subject": subject, "text": text_content, } return mailgun_send(mailgun_data)
def admin_new_subscription_notify(subscription): domain = Site.objects.get_current().domain admin_path = urlresolvers.reverse('subscription_manage_detail', args=( subscription.location.slug, subscription.id, )) text_content = '''Howdy,\n\nA new subscription for %s %s has been added for %d/mo starting %s.\n\nManage this subscription at %s%s.''' % ( subscription.user.first_name, subscription.user.last_name, subscription.price, str(subscription.start_date), domain, admin_path) recipients = [] for admin in subscription.location.house_admins.all(): if not admin.email in recipients: recipients.append(admin.email) subject = "[%s] Subscription Added for %s %s" % ( subscription.location.email_subject_prefix, subscription.user.first_name, subscription.user.last_name) mailgun_data = { "from": subscription.location.from_email(), "to": recipients, "subject": subject, "text": text_content, } return mailgun_send(mailgun_data)
def residents(request, location_slug): ''' email all residents at this location.''' # fail gracefully if location does not exist try: location = get_location(location_slug) except: # XXX TODO reject and bounce back to sender? logger.error('location not found') return HttpResponse(status=200) logger.debug('residents@ for location: %s' % location) # we think that message_headers is a list of strings header_txt = request.POST.get('message-headers') message_headers = json.loads(header_txt) message_header_keys = [item[0] for item in message_headers] # make sure this isn't an email we have already forwarded (cf. emailbombgate 2014) # A List-Id header will only be present if it has been added manually in # this function, ie, if we have already processed this message. if request.POST.get('List-Id') or 'List-Id' in message_header_keys: # mailgun requires a code 200 or it will continue to retry delivery logger.debug('List-Id header was found! Dropping message silently') return HttpResponse(status=200) #if 'Auto-Submitted' in message_headers or message_headers['Auto-Submitted'] != 'no': if 'Auto-Submitted' in message_header_keys: logger.info('message appears to be auto-submitted. reject silently') return HttpResponse(status=200) recipient = request.POST.get('recipient') from_address = request.POST.get('from') logger.debug('from: %s' % from_address) sender = request.POST.get('sender') logger.debug('sender: %s' % sender) subject = request.POST.get('subject') body_plain = request.POST.get('body-plain') body_html = request.POST.get('body-html') # Add all the residents at this location resident_emails = [] for r in location.residents(): resident_emails.append(r.email) # Now loop through all the emails and build the bcc list we will use. # This makes sure there are no duplicate emails. bcc_list = [] for email in resident_emails: if email not in bcc_list: bcc_list.append(email) logger.debug("bcc list: %s" % bcc_list) # Make sure this person can post to our list #if not sender in bcc_list: # # TODO - This shoud possibly send a response so they know they were blocked # logger.warn("Sender (%s) not allowed. Exiting quietly." % sender) # return HttpResponse(status=200) if sender in bcc_list: bcc_list.remove(sender) # Include attachements attachments = [] for attachment in request.FILES.values(): attachments.append(("attachment", attachment)) # prefix subject, but only if the prefix string isn't already in the # subject line (such as a reply) if subject.find(location.email_subject_prefix) < 0: prefix = "["+location.email_subject_prefix + "] " subject = prefix + subject logger.debug("subject: %s" % subject) # add in footer text_footer = '''\n\n-------------------------------------------\n*~*~*~* %s residents email list *~*~*~* '''% location.name body_plain = body_plain + text_footer if body_html: html_footer = '''<br><br>-------------------------------------------<br>*~*~*~* %s residents email list *~*~*~* '''% location.name body_html = body_html + html_footer # send the message list_address = "residents@%s.%s" % (location.slug, settings.LIST_DOMAIN) mailgun_data = {"from": from_address, "to": [recipient, ], "bcc": bcc_list, "subject": subject, "text": body_plain, "html": body_html, # attach some headers: LIST-ID, REPLY-TO, MSG-ID, precedence... # Precedence: list - helps some out of office auto responders know not to send their auto-replies. "h:List-Id": list_address, "h:Precedence": "list", # Reply-To: list email apparently has some religious debates # (http://www.gnu.org/software/mailman/mailman-admin/node11.html) but seems # to be common these days "h:Reply-To": list_address, } return mailgun_send(mailgun_data, attachments)
def event_published_notification(event, location): ''' notify event organizers and subscribed members that their event is live''' logger.debug("event_published_notification") event_short_title = event.title[0:50] if len(event.title) > 50: event_short_title = event_short_title + "..." # first notify organizers recipients = [organizer.email for organizer in event.organizers.all()] subject = '[' + location.email_subject_prefix + ']' + " Your event is now live: %s" % event_short_title from_address = location.from_email() plaintext = get_template('emails/event_published_notify.txt') c = { 'event': event, 'domain': Site.objects.get_current().domain, 'location': location, } body_plain = plaintext.render(c) mailgun_data = { "from": from_address, "to": recipients, "subject": subject, "text": body_plain, } status = mailgun_send(mailgun_data) # then notify subscribed user accounts of this event notify_published = EventNotifications.objects.filter(location_publish__in=[ location, ]) subscribed_users = [notify.user.email for notify in notify_published] subject = '[' + location.email_subject_prefix + ']' + " New event: %s" % event_short_title from_address = location.from_email() plaintext = get_template('emails/new_event_announce.txt') htmltext = get_template('emails/new_event_announce.html') domain = Site.objects.get_current().domain c_text = { 'event': event, 'domain': Site.objects.get_current().domain, 'location': location, } text_content = plaintext.render(c_text) c_html = { 'event': event, 'domain': Site.objects.get_current().domain, 'location': location, } html_content = htmltext.render(c_html) for subscriber in subscribed_users: # if it's a public event, or subscriber is in the community and it's a # community event, then let the subscriber know. private events are not # announced to subscribers. logger.debug(event.visibility) try: u = User.objects.get(email=subscriber) except: logger.error( 'There was an error retrieving the user associated with email address %s, likely because the email is not unique. Skipping this notification.' % subscriber) return if (event.visibility == Event.PUBLIC) or (event.visibility == Event.COMMUNITY and u in location.residents()): mailgun_data = { "from": from_address, "to": subscriber, "subject": subject, "text": text_content, "html": html_content, } status = mailgun_send(mailgun_data)
def residents(request, location_slug): ''' email all residents at this location.''' # fail gracefully if location does not exist try: location = get_location(location_slug) except: # XXX TODO reject and bounce back to sender? logger.error('location not found') return HttpResponse(status=200) logger.debug('residents@ for location: %s' % location) # we think that message_headers is a list of strings header_txt = request.POST.get('message-headers') message_headers = json.loads(header_txt) message_header_keys = [item[0] for item in message_headers] # make sure this isn't an email we have already forwarded (cf. emailbombgate 2014) # A List-Id header will only be present if it has been added manually in # this function, ie, if we have already processed this message. if request.POST.get('List-Id') or 'List-Id' in message_header_keys: # mailgun requires a code 200 or it will continue to retry delivery logger.debug('List-Id header was found! Dropping message silently') return HttpResponse(status=200) #if 'Auto-Submitted' in message_headers or message_headers['Auto-Submitted'] != 'no': if 'Auto-Submitted' in message_header_keys: logger.info('message appears to be auto-submitted. reject silently') return HttpResponse(status=200) recipient = request.POST.get('recipient') from_address = request.POST.get('from') logger.debug('from: %s' % from_address) sender = request.POST.get('sender') logger.debug('sender: %s' % sender) subject = request.POST.get('subject') body_plain = request.POST.get('body-plain') body_html = request.POST.get('body-html') # Add all the residents at this location resident_emails = [] for r in location.residents(): resident_emails.append(r.email) # Now loop through all the emails and build the bcc list we will use. # This makes sure there are no duplicate emails. bcc_list = [] for email in resident_emails: if email not in bcc_list: bcc_list.append(email) logger.debug("bcc list: %s" % bcc_list) # Make sure this person can post to our list #if not sender in bcc_list: # # TODO - This shoud possibly send a response so they know they were blocked # logger.warn("Sender (%s) not allowed. Exiting quietly." % sender) # return HttpResponse(status=200) if sender in bcc_list: bcc_list.remove(sender) # Include attachements attachments = [] for attachment in request.FILES.values(): attachments.append(("attachment", attachment)) # prefix subject, but only if the prefix string isn't already in the # subject line (such as a reply) if subject.find(location.email_subject_prefix) < 0: prefix = "[" + location.email_subject_prefix + "] " subject = prefix + subject logger.debug("subject: %s" % subject) # add in footer text_footer = '''\n\n-------------------------------------------\n*~*~*~* %s residents email list *~*~*~* ''' % location.name body_plain = body_plain + text_footer if body_html: html_footer = '''<br><br>-------------------------------------------<br>*~*~*~* %s residents email list *~*~*~* ''' % location.name body_html = body_html + html_footer # send the message list_address = "residents@%s.%s" % (location.slug, settings.LIST_DOMAIN) mailgun_data = { "from": from_address, "to": [ recipient, ], "bcc": bcc_list, "subject": subject, "text": body_plain, "html": body_html, # attach some headers: LIST-ID, REPLY-TO, MSG-ID, precedence... # Precedence: list - helps some out of office auto responders know not to send their auto-replies. "h:List-Id": list_address, "h:Precedence": "list", # Reply-To: list email apparently has some religious debates # (http://www.gnu.org/software/mailman/mailman-admin/node11.html) but seems # to be common these days "h:Reply-To": list_address, } return mailgun_send(mailgun_data, attachments)
def test80085(request, location_slug): ''' test route ''' # fail gracefully if location does not exist try: location = get_location(location_slug) except: # XXX TODO reject and bounce back to sender? return HttpResponse(status=200) logger.debug('test80085@ for location: %s' % location) logger.debug(request.POST) logger.debug(request.FILES) # we think that message_headers is a list of strings header_txt = request.POST.get('message-headers') message_headers = json.loads(header_txt) message_header_keys = [item[0] for item in message_headers] # make sure this isn't an email we have already forwarded (cf. emailbombgate 2014) # A List-Id header will only be present if it has been added manually in # this function, ie, if we have already processed this message. if request.POST.get('List-Id') or 'List-Id' in message_header_keys: # mailgun requires a code 200 or it will continue to retry delivery logger.debug('List-Id header was found! Dropping message silently') return HttpResponse(status=200) #if 'Auto-Submitted' in message_headers or message_headers['Auto-Submitted'] != 'no': if 'Auto-Submitted' in message_header_keys: logger.info('message appears to be auto-submitted. reject silently') return HttpResponse(status=200) recipient = request.POST.get('recipient') to = request.POST.get('To') from_address = request.POST.get('from') logger.debug('from: %s' % from_address) sender = request.POST.get('sender') logger.debug('sender: %s' % sender) subject = request.POST.get('subject') body_plain = request.POST.get('body-plain') body_html = request.POST.get('body-html') # retrieve the current house admins for this location bcc_list = ['*****@*****.**', '*****@*****.**'] logger.debug("bcc list: %s" % bcc_list) # Make sure this person can post to our list #if not sender in bcc_list: # # TODO - This shoud possibly send a response so they know they were blocked # logger.warn("Sender (%s) not allowed. Exiting quietly." % sender) # return HttpResponse(status=200) # usually we would remove the sender from receiving the email but because # we're testing, let 'em have it. #if sender in bcc_list: # bcc_list.remove(sender) # pass through attachments # logger.debug(request) # logger.debug(request.FILES) # for attachment in request.FILES.values(): # # JKS NOTE! this does NOT work with unicode-encoded data. i'm not # # actually sure that we should *expect* to receive unicode-encoded # # attachments, but it definitely breaks (which i disocvered because # # mailgun sends its test POST with a unicode-encoded attachment). # a_file = default_storage.save(attachment.name, ContentFile(attachment.read())) # attachments = {} # num = 0 # for attachment in request.FILES.values(): # attachments["attachment-%d" % num] = (attachment.name, default_storage.open(attachment.name, 'rb').read()) # #default_storage.delete(attachment.name) # num+= 1 attachments = [] for attachment in request.FILES.values(): attachments.append(("inline", attachment)) # prefix subject, but only if the prefix string isn't already in the # subject line (such as a reply) if subject.find('EN Test') < 0: prefix = "[EN Test!] " subject = prefix + subject logger.debug("subject: %s" % subject) # add in footer text_footer = '''\n\n-------------------------------------------\nYou are receiving this email because someone at Embassy Network wanted to use you as a guinea pig. %mailing_list_unsubscribe_url%''' body_plain = body_plain + text_footer if body_html: html_footer = '''<br><br>-------------------------------------------<br>You are receiving this email because someone at Embassy Network wanted to use you as a guinea pig.''' body_html = body_html + html_footer # send the message list_address = "test80085@" + location.slug + ".mail.embassynetwork.com" mailgun_data = { "from": from_address, "to": [ recipient, ], "bcc": bcc_list, "subject": subject, "text": body_plain, "html": body_html, # attach some headers: LIST-ID, REPLY-TO, MSG-ID, precedence... # Precedence: list - helps some out of office auto responders know not to send their auto-replies. "h:List-Id": list_address, "h:Precedence": "list", # Reply-To: list email apparently has some religious debates # (http://www.gnu.org/software/mailman/mailman-admin/node11.html) but seems # to be common these days "h:Reply-To": from_address } return mailgun_send(mailgun_data, attachments)
def admin_daily_update(location): # this is split out by location because each location has a timezone that affects the value of 'today' today = timezone.localtime(timezone.now()).date() arriving_today = Use.objects.filter(location=location).filter( arrive=today).filter(status='confirmed') maybe_arriving_today = Use.objects.filter(location=location).filter( arrive=today).filter(status='approved') pending_now = Use.objects.filter(location=location).filter( status='pending') approved_now = Use.objects.filter(location=location).filter( status='approved') departing_today = Use.objects.filter(location=location).filter( depart=today).filter(status='confirmed') events_today = published_events_today_local(location=location) pending_or_feedback = events_pending(location=location) # if there are subscriptions ready for billing, the bills should have been # generated by another task. this is for notification purposes only so the # admins know the check 'em out. subscriptions_ready = Subscription.objects.ready_for_billing( location, target_date=today) if not arriving_today and not departing_today and not events_today and not maybe_arriving_today and not pending_now and not approved_now and not subscriptions_ready: logger.debug("Nothing happening today at %s, skipping daily email" % location.name) return subject = "[%s] %s Events and Guests" % (location.email_subject_prefix, today) admins_emails = [] for admin in location.house_admins.all(): if not admin.email in admins_emails: admins_emails.append(admin.email) if len(admins_emails) == 0: logger.debug('%s: No admins to send to' % location.slug) return None c = { 'today': today, 'domain': Site.objects.get_current().domain, 'location': location, 'arriving': arriving_today, 'maybe_arriving': maybe_arriving_today, 'pending_now': pending_now, 'approved_now': approved_now, 'departing': departing_today, 'events_today': events_today, 'events_pending': pending_or_feedback['pending'], 'events_feedback': pending_or_feedback['feedback'], 'subscriptions_ready': subscriptions_ready, } text_content, html_content = render_templates( c, location, LocationEmailTemplate.ADMIN_DAILY) mailgun_data = { "from": location.from_email(), "to": admins_emails, "subject": subject, "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def event_message(request, location_slug=None): ''' Message event admins and organizers via an email alias.''' if not request.method == 'POST': return HttpResponseRedirect('/404') recipient = request.POST.get('recipient') from_address = request.POST.get('from') sender = request.POST.get('sender') subject = request.POST.get('subject') body_plain = request.POST.get('body-plain') body_html = request.POST.get('body-html') # get the event info and make sure the event exists # we know that the route is always in the form eventXX, where XX is the # event id. alias = recipient.split('@')[0] logger.debug("event_message: alias=%s" % alias) event = None try: event_id = int(alias[5:]) logger.debug("event_message: event_id=%s" % event_id) event = Event.objects.get(id=event_id) except: pass if not event: logger.warn("Event (%s) not found. Exiting quietly." % alias) return HttpResponse(status=200) # Do some sanity checkint so we don't mailbomb everyone header_txt = request.POST.get('message-headers') message_headers = json.loads(header_txt) message_header_keys = [item[0] for item in message_headers] # make sure this isn't an email we have already forwarded (cf. emailbombgate 2014) # A List-Id header will only be present if it has been added manually in # this function, ie, if we have already processed this message. if request.POST.get('List-Id') or 'List-Id' in message_header_keys: logger.debug('List-Id header was found! Dropping message silently') return HttpResponse(status=200) # If 'Auto-Submitted' in message_headers or message_headers['Auto-Submitted'] != 'no': if 'Auto-Submitted' in message_header_keys: logger.info('message appears to be auto-submitted. reject silently') return HttpResponse(status=200) # find the event organizers and admins organizers = event.organizers.all() location_event_admin = EventAdminGroup.objects.get(location=event.location) admins = location_event_admin.users.all() # Build our bcc list bcc_list = [] for organizer in organizers: if organizer.email not in bcc_list: bcc_list.append(organizer.email) for admin in admins: if admin.email not in bcc_list: bcc_list.append(admin.email) logger.debug("BCC List: %s" % bcc_list) # Make sure this person can post to our list if not sender in bcc_list: # TODO - This shoud possibly send a response so they know they were blocked logger.warn("Sender (%s) not allowed. Exiting quietly." % sender) return HttpResponse(status=200) bcc_list.remove(sender) # prefix subject if subject.find('[Event Discussion') < 0: prefix = '[Event Discussion: %s] ' % event.slug[0:30] subject = prefix + subject # Add in footer #domain = Site.objects.get_current().domain event_url = request.build_absolute_uri(urlresolvers.reverse('gather_view_event', args=(event.location.slug, event.id, event.slug))) footer_msg = "You are receving this email because you are one of the organizers or an event admin at this location. Visit this event online at %s" % event_url body_plain = body_plain + "\n\n-------------------------------------------\n" + footer_msg if body_html: body_html = body_html + "<br><br>-------------------------------------------<br>" + footer_msg # send the message mailgun_data={"from": from_address, "to": [recipient, ], "bcc": bcc_list, "subject": subject, "text": body_plain, "html": body_html, "h:Reply-To": recipient, "h:List-Id": recipient, "h:Precedence": "list", } return mailgun_send(mailgun_data)
def event_published_notification(event, location): ''' notify event organizers and subscribed members that their event is live''' logger.debug("event_published_notification") event_short_title = event.title[0:50] if len(event.title) > 50: event_short_title = event_short_title + "..." # first notify organizers recipients = [organizer.email for organizer in event.organizers.all()] subject = '[' + location.email_subject_prefix + ']' + " Your event is now live: %s" % event_short_title from_address = location.from_email() plaintext = get_template('emails/event_published_notify.txt') c = { 'event': event, 'domain' : Site.objects.get_current().domain, 'location': location, } body_plain = plaintext.render(c) mailgun_data = { "from": from_address, "to": recipients, "subject": subject, "text": body_plain, } status = mailgun_send(mailgun_data) # then notify subscribed user accounts of this event notify_published = EventNotifications.objects.filter(location_publish__in=[location,]) subscribed_users = [notify.user.email for notify in notify_published] subject = '[' + location.email_subject_prefix + ']' + " New event: %s" % event_short_title from_address = location.from_email() plaintext = get_template('emails/new_event_announce.txt') htmltext = get_template('emails/new_event_announce.html') domain = Site.objects.get_current().domain c_text = { 'event': event, 'domain' : Site.objects.get_current().domain, 'location': location, } text_content = plaintext.render(c_text) c_html = { 'event': event, 'domain' : Site.objects.get_current().domain, 'location': location, } html_content = htmltext.render(c_html) for subscriber in subscribed_users: # if it's a public event, or subscriber is in the community and it's a # community event, then let the subscriber know. private events are not # announced to subscribers. logger.debug(event.visibility) try: u = User.objects.get(email=subscriber) except: logger.error('There was an error retrieving the user associated with email address %s, likely because the email is not unique. Skipping this notification.' % subscriber) return if (event.visibility == Event.PUBLIC) or (event.visibility == Event.COMMUNITY and u in location.residents()): mailgun_data={"from": from_address, "to": subscriber, "subject": subject, "text": text_content, "html": html_content, } status = mailgun_send(mailgun_data)
def guest_welcome(use): ''' Send guest a welcome email''' # this is split out by location because each location has a timezone that affects the value of 'today' domain = Site.objects.get_current().domain location = use.location intersecting_uses = Use.objects.filter(arrive__gte=use.arrive).filter( depart__lte=use.depart) residents = location.residents() intersecting_events = Event.objects.filter(location=location).filter( start__gte=use.arrive).filter(end__lte=use.depart) profiles = None day_of_week = weekday_number_to_name[use.arrive.weekday()] c = { 'first_name': use.user.first_name, 'day_of_week': day_of_week, 'location': use.location, 'use': use, 'current_email': 'current@%s.mail.embassynetwork.com' % location.slug, 'site_url': "https://" + domain + urlresolvers.reverse('location_detail', args=(location.slug, )), 'events_url': "https://" + domain + urlresolvers.reverse('gather_upcoming_events', args=(location.slug, )), 'profile_url': "https://" + domain + urlresolvers.reverse('user_detail', args=(use.user.username, )), 'booking_url': "https://" + domain + urlresolvers.reverse('booking_detail', args=( location.slug, use.booking.id, )), 'intersecting_bookings': intersecting_uses, 'intersecting_events': intersecting_events, 'residents': residents, } text_content, html_content = render_templates( c, location, LocationEmailTemplate.WELCOME) mailgun_data = { "from": use.location.from_email(), "to": [use.user.email], "subject": "[%s] See you on %s" % (use.location.email_subject_prefix, day_of_week), "text": text_content, } if html_content: mailgun_data["html"] = html_content return mailgun_send(mailgun_data)
def test80085(request, location_slug): ''' test route ''' # fail gracefully if location does not exist try: location = get_location(location_slug) except: # XXX TODO reject and bounce back to sender? return HttpResponse(status=200) logger.debug('test80085@ for location: %s' % location) logger.debug(request.POST) logger.debug(request.FILES) # we think that message_headers is a list of strings header_txt = request.POST.get('message-headers') message_headers = json.loads(header_txt) message_header_keys = [item[0] for item in message_headers] # make sure this isn't an email we have already forwarded (cf. emailbombgate 2014) # A List-Id header will only be present if it has been added manually in # this function, ie, if we have already processed this message. if request.POST.get('List-Id') or 'List-Id' in message_header_keys: # mailgun requires a code 200 or it will continue to retry delivery logger.debug('List-Id header was found! Dropping message silently') return HttpResponse(status=200) #if 'Auto-Submitted' in message_headers or message_headers['Auto-Submitted'] != 'no': if 'Auto-Submitted' in message_header_keys: logger.info('message appears to be auto-submitted. reject silently') return HttpResponse(status=200) recipient = request.POST.get('recipient') to = request.POST.get('To') from_address = request.POST.get('from') logger.debug('from: %s' % from_address) sender = request.POST.get('sender') logger.debug('sender: %s' % sender) subject = request.POST.get('subject') body_plain = request.POST.get('body-plain') body_html = request.POST.get('body-html') # retrieve the current house admins for this location bcc_list = ['*****@*****.**', '*****@*****.**'] logger.debug("bcc list: %s" % bcc_list) # Make sure this person can post to our list #if not sender in bcc_list: # # TODO - This shoud possibly send a response so they know they were blocked # logger.warn("Sender (%s) not allowed. Exiting quietly." % sender) # return HttpResponse(status=200) # usually we would remove the sender from receiving the email but because # we're testing, let 'em have it. #if sender in bcc_list: # bcc_list.remove(sender) # pass through attachments # logger.debug(request) # logger.debug(request.FILES) # for attachment in request.FILES.values(): # # JKS NOTE! this does NOT work with unicode-encoded data. i'm not # # actually sure that we should *expect* to receive unicode-encoded # # attachments, but it definitely breaks (which i disocvered because # # mailgun sends its test POST with a unicode-encoded attachment). # a_file = default_storage.save(attachment.name, ContentFile(attachment.read())) # attachments = {} # num = 0 # for attachment in request.FILES.values(): # attachments["attachment-%d" % num] = (attachment.name, default_storage.open(attachment.name, 'rb').read()) # #default_storage.delete(attachment.name) # num+= 1 attachments = [] for attachment in request.FILES.values(): attachments.append(("inline", attachment)) # prefix subject, but only if the prefix string isn't already in the # subject line (such as a reply) if subject.find('EN Test') < 0: prefix = "[EN Test!] " subject = prefix + subject logger.debug("subject: %s" % subject) # add in footer text_footer = '''\n\n-------------------------------------------\nYou are receiving this email because someone at Embassy Network wanted to use you as a guinea pig. %mailing_list_unsubscribe_url%''' body_plain = body_plain + text_footer if body_html: html_footer = '''<br><br>-------------------------------------------<br>You are receiving this email because someone at Embassy Network wanted to use you as a guinea pig.''' body_html = body_html + html_footer # send the message list_address = "test80085@"+location.slug+".mail.embassynetwork.com" mailgun_data = {"from": from_address, "to": [recipient, ], "bcc": bcc_list, "subject": subject, "text": body_plain, "html": body_html, # attach some headers: LIST-ID, REPLY-TO, MSG-ID, precedence... # Precedence: list - helps some out of office auto responders know not to send their auto-replies. "h:List-Id": list_address, "h:Precedence": "list", # Reply-To: list email apparently has some religious debates # (http://www.gnu.org/software/mailman/mailman-admin/node11.html) but seems # to be common these days "h:Reply-To": from_address } return mailgun_send(mailgun_data, attachments)
def event_message(request, location_slug=None): ''' Message event admins and organizers via an email alias.''' if not request.method == 'POST': return HttpResponseRedirect('/404') recipient = request.POST.get('recipient') from_address = request.POST.get('from') sender = request.POST.get('sender') subject = request.POST.get('subject') body_plain = request.POST.get('body-plain') body_html = request.POST.get('body-html') # get the event info and make sure the event exists # we know that the route is always in the form eventXX, where XX is the # event id. alias = recipient.split('@')[0] logger.debug("event_message: alias=%s" % alias) event = None try: event_id = int(alias[5:]) logger.debug("event_message: event_id=%s" % event_id) event = Event.objects.get(id=event_id) except: pass if not event: logger.warn("Event (%s) not found. Exiting quietly." % alias) return HttpResponse(status=200) # Do some sanity checkint so we don't mailbomb everyone header_txt = request.POST.get('message-headers') message_headers = json.loads(header_txt) message_header_keys = [item[0] for item in message_headers] # make sure this isn't an email we have already forwarded (cf. emailbombgate 2014) # A List-Id header will only be present if it has been added manually in # this function, ie, if we have already processed this message. if request.POST.get('List-Id') or 'List-Id' in message_header_keys: logger.debug('List-Id header was found! Dropping message silently') return HttpResponse(status=200) # If 'Auto-Submitted' in message_headers or message_headers['Auto-Submitted'] != 'no': if 'Auto-Submitted' in message_header_keys: logger.info('message appears to be auto-submitted. reject silently') return HttpResponse(status=200) # find the event organizers and admins organizers = event.organizers.all() location_event_admin = EventAdminGroup.objects.get(location=event.location) admins = location_event_admin.users.all() # Build our bcc list bcc_list = [] for organizer in organizers: if organizer.email not in bcc_list: bcc_list.append(organizer.email) for admin in admins: if admin.email not in bcc_list: bcc_list.append(admin.email) logger.debug("BCC List: %s" % bcc_list) # Make sure this person can post to our list if not sender in bcc_list: # TODO - This shoud possibly send a response so they know they were blocked logger.warn("Sender (%s) not allowed. Exiting quietly." % sender) return HttpResponse(status=200) bcc_list.remove(sender) # prefix subject if subject.find('[Event Discussion') < 0: prefix = '[Event Discussion: %s] ' % event.slug[0:30] subject = prefix + subject # Add in footer #domain = Site.objects.get_current().domain event_url = request.build_absolute_uri( urlresolvers.reverse('gather_view_event', args=(event.location.slug, event.id, event.slug))) footer_msg = "You are receving this email because you are one of the organizers or an event admin at this location. Visit this event online at %s" % event_url body_plain = body_plain + "\n\n-------------------------------------------\n" + footer_msg if body_html: body_html = body_html + "<br><br>-------------------------------------------<br>" + footer_msg # send the message mailgun_data = { "from": from_address, "to": [ recipient, ], "bcc": bcc_list, "subject": subject, "text": body_plain, "html": body_html, "h:Reply-To": recipient, "h:List-Id": recipient, "h:Precedence": "list", } return mailgun_send(mailgun_data)