Example #1
0
def instance_open(request):
	'''
		Records an email open
	'''
	instance_id   = request.GET.get('instance',  None)
	recipient_id  = request.GET.get('recipient', None)
	mac           = request.GET.get('mac',       None)

	if recipient_id and mac and instance_id is not None:
		try:
			instance_id  = int(instance_id)
			recipient_id = int(recipient_id)
		except ValueError:
			# corrupted
			pass
		else:
			if mac == calc_open_mac(recipient_id, instance_id):
				try:
					recipient = Recipient.objects.get(id=recipient_id)
					instance  = Instance.objects.get(id=instance_id)
					InstanceOpen.objects.get(recipient=recipient, instance=instance)
				except Recipient.DoesNotExist:
					# strange
					log.error('bad recipient')
					pass
				except Instance.DoesNotExist:
					# also strange
					log.error('bad instance')
					pass
				except InstanceOpen.DoesNotExist:
					instance_open = InstanceOpen(recipient=recipient, instance=instance)
					instance_open.save()
					log.debug('open saved')
	return HttpResponse(settings.DOT, content_type='image/png')
Example #2
0
	def _test_open_tracking(self, instance):
		'''
			Test the open tracking. Must be called in the context of an email instance.
		'''
		client   = Client()
		response = client.get('?'.join([
			reverse('manager-email-open'),
			urllib.urlencode({
				'recipient':self.recipient.pk,
				'instance' :instance.pk,
				'mac'      :calc_open_mac(self.recipient.pk, instance.pk)
			})
		]))
		self.assertTrue(response.status_code == 200)
		opens = InstanceOpen.objects.all()
		self.assertTrue(opens.count() == 1)
Example #3
0
    def _test_open_tracking(self, instance):
        '''
			Test the open tracking. Must be called in the context of an email instance.
		'''
        client = Client()
        response = client.get('?'.join([
            reverse('manager-email-open'),
            urllib.parse.urlencode({
                'recipient':
                self.recipient.pk,
                'instance':
                instance.pk,
                'mac':
                calc_open_mac(self.recipient.pk, instance.pk)
            })
        ]))
        self.assertTrue(response.status_code == 200)
        opens = InstanceOpen.objects.all()
        self.assertTrue(opens.count() == 1)
Example #4
0
            def run(self):
                amazon             = None
                reconnect          = False
                reconnect_counter  = 0
                error              = False
                error_counter      = 0
                rate_limit_counter = 0

                while True:
                    if recipient_details_queue.empty():
                        log.debug('%s queue empty, exiting.' % self.name)
                        break

                    if sender_stop.is_set():
                        log.debug('%s receieved termination signal.' % self.name)
                        while not recipient_details_queue.empty():
                            recipient_details_queue.get()
                            recipient_details_queue.task_done()
                        break

                    recipient_details = recipient_details_queue.get()

                    try:
                        if amazon is None or reconnect:
                            try:
                                amazon = smtplib.SMTP_SSL(settings.AMAZON_SMTP['host'], settings.AMAZON_SMTP['port'])
                                amazon.login(settings.AMAZON_SMTP['username'], settings.AMAZON_SMTP['password'])
                            except:
                                if reconnect_counter == SendingThread._AMAZON_RECONNECT_THRESHOLD:
                                    log.debug('%s, reached reconnect threshold, exiting')
                                    raise
                                reconnect_counter += 1
                                reconnect         = True
                                continue
                            else:
                                reconnect = False

                        # Customize the email for this recipient
                        customized_html = recipient_details.instance.sent_html
                        # Replace template placeholders
                        delimiter = recipient_details.instance.email.replace_delimiter
                        for placeholder in placeholders:
                            replacement = ''
                            if placeholder.lower() != 'unsubscribe':
                                if recipient_attributes[recipient_details.recipient.pk][placeholder] is None:
                                    log.error('Recipient %s is missing attribute %s' % (str(recipient_details.recipient), placeholder))
                                else:
                                    replacement = recipient_attributes[recipient_details.recipient.pk][placeholder]
                                customized_html = customized_html.replace(delimiter + placeholder + delimiter, replacement)
                        # URL Tracking
                        if recipient_details.instance.urls_tracked:
                            for url in tracking_urls:
                                tracking_url = '?'.join([
                                    settings.PROJECT_URL + reverse('manager-email-redirect'),
                                    urllib.urlencode({
                                        'instance'  :recipient_details.instance.pk,
                                        'recipient' :recipient_details.recipient.pk,
                                        'url'       :urllib.quote(url.name),
                                        'position'  :url.position,
                                        # The mac uniquely identifies the recipient and acts as a secure integrity check
                                        'mac'       :calc_url_mac(url.name, url.position, recipient_details.recipient.pk, recipient_details.instance.pk)
                                    })
                                ])

                                customized_html = customized_html.replace(
                                    'href="' + url.name + '"',
                                    'href="' + tracking_url + '"',
                                    1
                                )
                        # Open Tracking
                        if recipient_details.instance.opens_tracked:
                            customized_html += '<img src="%s" />' % '?'.join([
                                settings.PROJECT_URL + reverse('manager-email-open'),
                                urllib.urlencode({
                                    'recipient':recipient_details.recipient.pk,
                                    'instance' :recipient_details.instance.pk,
                                    'mac'      :calc_open_mac(recipient_details.recipient.pk, recipient_details.instance.pk)
                                })
                            ])
                        # Unsubscribe link
                        customized_html = re.sub(
                            re.escape(delimiter) + 'UNSUBSCRIBE' + re.escape(delimiter),
                            '<a href="%s" style="color:blue;text-decoration:none;">unsubscribe</a>' % recipient_details.recipient.unsubscribe_url,
                            customized_html)

                        # Construct the message
                        msg            = MIMEMultipart('alternative')
                        msg['subject'] = subject
                        msg['From']    = display_from
                        msg['To']      = recipient_details.recipient.email_address
                        msg.attach(MIMEText(customized_html, 'html', _charset='us-ascii'))
                        if text is not None:
                            msg.attach(MIMEText(text, 'plain', _charset='us-ascii' ))

                        log.debug('thread: %s, email: %s' % (self.name, recipient_details.recipient.email_address))
                        try:
                            amazon.sendmail(real_from, recipient_details.recipient.email_address, msg.as_string())
                        except smtplib.SMTPResponseException, e:
                            if e.smtp_error.find('Maximum sending rate exceeded') >= 0:
                                recipient_details_queue.put(recipient_details)
                                log.debug('thread %s, maximum sending rate exceeded, sleeping for a bit')
                                time.sleep(float(1) + random.random())
                            else:
                                recipient_details.exception_msg = str(e)
                        except smtplib.SMTPServerDisconnected:
                            # Connection error
                            log.debug('thread %s, connection error, sleeping for a bit')
                            time.sleep(float(1) + random.random())
                            recipient_details_queue.put(recipient_details)
                            reconnect = True
                        else:
                            recipient_details.when = datetime.now()
                        finally:
                            recipient_details.save()
                    except Exception, e:
                        if error_counter == SendingThread._ERROR_THRESHOLD:
                            recipient_details_queue.task_done()
                            log.debug('%s, reached error threshold, exiting')
                            with recipient_details_queue.mutex:
                                recipient_details_queue.queue.clear()
                                return
                        error_counter += 1
                        log.exception('%s exception' % self.name)