Exemplo n.º 1
0
	def create_offer(self, captcha_response, name, country, amount, min_amount, charity, email, expiration):
		errors = util.Template('errors-and-warnings.json')
		if not self.automation_mode and not self._captcha.is_legit(self._ip_address, captcha_response):
			raise DonationException(errors.json('bad captcha'))

		name, country, amount, min_amount, charity, email, expires_ts = self._validate_offer(name, country, amount, min_amount, charity, email, expiration)

		secret = create_secret()
		# Do NOT return this secret to the client via this method.
		# Only put it in the email, so that having the link acts as email address verification.

		with self._database.connect() as db:
			offer = entities.Offer.create(db, secret, name, email, country.id, amount, min_amount, charity.id, expires_ts)
			eventlog.created_offer(db, offer)

		if self.automation_mode:
			return offer

		replacements = {
			'{%NAME%}': offer.name,
			'{%SECRET%}': offer.secret,
			'{%CHARITY%}': offer.charity.name,
			'{%CURRENCY%}': offer.country.currency.iso,
			'{%AMOUNT%}': offer.amount,
			'{%MIN_AMOUNT%}': offer.min_amount,
		}
		self._mail.send(
			util.Template('email-subjects.json').json('new-post-email'),
			util.Template('new-post-email.txt').replace(replacements).content,
			html=util.Template('new-post-email.html').replace(replacements).content,
			to=email
		)

		return None
Exemplo n.º 2
0
    def _get_gift_aid_insert(offer, to_charity_amount, charity_receiving):
        if offer.country.gift_aid_multiplier <= 1:
            return "", ""

        # hardcoding might be bad practice,
        # but if we have to do more work due to more gift aid, it's not such a bad thing,
        # I'm also happy to move this to the database eventually
        gift_aid_name = "UK government Gift Aid"
        if offer.country.iso_name == "IE":
            gift_aid_name = "Irish government contribution"

        replacements = {
            '{%GIFT_AID_NAME%}': gift_aid_name,
            '{%GIFT_AID_AMOUNT%}': offer.country.gift_aid,
            '{%TO_CHARITY%}': to_charity_amount,
            '{%CURRENCY%}': offer.country.currency.iso,
            '{%CHARITY_NAME%}': charity_receiving,
        }

        txt = util.Template('gift-aid-insert.txt').replace(
            replacements).content
        html = util.Template('gift-aid-insert.html').replace(
            replacements).content

        return txt, html
Exemplo n.º 3
0
	def _send_mail_about_expired_offer(self, offer):
		newExpirey = offer.expires_ts + (offer.expires_ts - offer.created_ts)
		replacements = {
			'{%NAME%}': offer.name,
			'{%AMOUNT%}': offer.amount,
			'{%MIN_AMOUNT%}': offer.min_amount,
			'{%CURRENCY%}': offer.country.currency.iso,
			'{%CHARITY%}': offer.charity.name,
			'{%ARGS%}': '#%s' % urllib.parse.quote(json.dumps({
				'name': offer.name,
				'country': offer.country_id,
				'amount': offer.amount,
				'min_amount': offer.min_amount,
				'charity': offer.charity_id,
				'email': offer.email,
				'expires': {
					'day': newExpirey.day,
					'month': newExpirey.month,
					'year': newExpirey.year,
				}
			}))
		}

		self._mail.send(
			util.Template('email-subjects.json').json('offer-expired-email'),
			util.Template('offer-expired-email.txt').replace(replacements).content,
			html=util.Template('offer-expired-email.html').replace(replacements).content,
			to=offer.email
		)
Exemplo n.º 4
0
    def _send_mail_about_expired_offer(self, offer):
        replacements = {
            '{%NAME%}':
            offer.name,
            '{%AMOUNT%}':
            offer.amount,
            '{%MIN_AMOUNT%}':
            offer.min_amount,
            '{%CURRENCY%}':
            offer.country.currency.iso,
            '{%CHARITY%}':
            offer.charity.name,
            '{%ARGS%}':
            '#%s' % urllib.parse.quote(
                json.dumps({
                    'country': offer.country_id,
                    'amount': offer.amount,
                    'charity': offer.charity_id,
                    'email': offer.email,
                }))
        }

        self._mail.send(
            util.Template('email-subjects.json').json('offer-expired-email'),
            util.Template('offer-expired-email.txt').replace(
                replacements).content,
            html=util.Template('offer-expired-email.html').replace(
                replacements).content,
            to=offer.email)
Exemplo n.º 5
0
	def send_contact_message(self, captcha_response, message, name=None, email=None):
		if not self.automation_mode and not self._captcha.is_legit(self._ip_address, captcha_response):
			raise DonationException(
				util.Template('errors-and-warnings.json').json('bad captcha')
			)

		tmp = util.Template('contact-email.txt')
		tmp.replace({
			'{%IP_ADDRESS%}': self._ip_address,
			'{%COUNTRY%}': self._geoip.lookup(self._ip_address),
			'{%NAME%}': name or 'n/a',
			'{%EMAIL%}': email or 'n/a',
			'{%MESSAGE%}': message.strip(),
		})

		send_to = self._config.contact_message_receivers.get('to', [])
		send_cc = self._config.contact_message_receivers.get('cc', [])
		send_bcc = self._config.contact_message_receivers.get('bcc', [])

		with self._database.connect() as db:
			eventlog.sent_contact_message(db, tmp.content, send_to, send_cc, send_bcc)

		self._mail.send(
			'Message for donationswap.eahub.org',
			tmp.content,
			to=send_to,
			cc=send_cc,
			bcc=send_bcc
		)
Exemplo n.º 6
0
    def _send_mail_about_match(self, my_offer, their_offer, match_secret):
        my_actual_amount, _ = self._get_actual_amounts(my_offer, their_offer)

        replacements = {
            '{%YOUR_NAME%}': my_offer.name,
            '{%YOUR_CHARITY%}': my_offer.charity.name,
            '{%YOUR_AMOUNT%}': my_offer.amount,
            '{%YOUR_MIN_AMOUNT%}': my_offer.min_amount,
            '{%YOUR_ACTUAL_AMOUNT%}': my_actual_amount,
            '{%YOUR_CURRENCY%}': my_offer.country.currency.iso,
            '{%THEIR_CHARITY%}': their_offer.charity.name,
            '{%SECRET%}': '%s%s' % (my_offer.secret, match_secret),
            # Do NOT put their email address here.
            # Wait until both parties approved the match.
        }

        logging.info('Sending match email to %s.', my_offer.email)

        self._mail.send(
            util.Template('email-subjects.json').json('match-suggested-email'),
            util.Template('match-suggested-email.txt').replace(
                replacements).content,
            html=util.Template('match-suggested-email.html').replace(
                replacements).content,
            to=my_offer.email)
Exemplo n.º 7
0
	def test_new_post_email(self):
		placeholders = [
			'{%NAME%}',
			'{%SECRET%}',
			'{%CHARITY%}',
			'{%CURRENCY%}',
			'{%AMOUNT%}',
			'{%MIN_AMOUNT%}',
		]
		txt = util.Template('new-post-email.txt').content
		self._check_expected_placeholders(txt, placeholders)
		txt = util.Template('new-post-email.html').content
		self._check_expected_placeholders(txt, placeholders)
Exemplo n.º 8
0
	def test_match_suggested_email(self):
		placeholders = [
			'{%YOUR_NAME%}',
			'{%YOUR_CHARITY%}',
			'{%YOUR_AMOUNT%}',
			'{%YOUR_MIN_AMOUNT%}',
			'{%YOUR_ACTUAL_AMOUNT%}',
			'{%YOUR_CURRENCY%}',
			'{%THEIR_CHARITY%}',
			'{%SECRET%}',
		]
		txt = util.Template('match-suggested-email.txt').content
		self._check_expected_placeholders(txt, placeholders)
		txt = util.Template('match-suggested-email.html').content
		self._check_expected_placeholders(txt, placeholders)
Exemplo n.º 9
0
	def test_match_appoved_email(self):
		placeholders_txt = [
			'{%NAME_A%}',
			'{%COUNTRY_A%}',
			'{%CHARITY_A%}',
			'{%ACTUAL_AMOUNT_A%}',
			'{%CURRENCY_A%}',
			'{%EMAIL_A%}',
			'{%INSTRUCTIONS_A%}',
			'{%NAME_B%}',
			'{%COUNTRY_B%}',
			'{%CHARITY_B%}',
			'{%ACTUAL_AMOUNT_B%}',
			'{%CURRENCY_B%}',
			'{%EMAIL_B%}',
			'{%INSTRUCTIONS_B%}',
			'{%ONE_CURRENCY_A_AS_B%}',
			'{%TO_CHARITY_A%}',
			'{%TO_CHARITY_B%}',
			'{%GIFT_AID_INSERT_A_TXT%}',
			'{%GIFT_AID_INSERT_B_TXT%}',
		]
		placeholders_html = [
			'{%NAME_A%}',
			'{%COUNTRY_A%}',
			'{%CHARITY_A%}',
			'{%ACTUAL_AMOUNT_A%}',
			'{%CURRENCY_A%}',
			'{%EMAIL_A%}',
			'{%INSTRUCTIONS_A%}',
			'{%NAME_B%}',
			'{%COUNTRY_B%}',
			'{%CHARITY_B%}',
			'{%ACTUAL_AMOUNT_B%}',
			'{%CURRENCY_B%}',
			'{%EMAIL_B%}',
			'{%INSTRUCTIONS_B%}',
			'{%ONE_CURRENCY_A_AS_B%}',
			'{%TO_CHARITY_A%}',
			'{%TO_CHARITY_B%}',
			'{%GIFT_AID_INSERT_A_HTML%}',
			'{%GIFT_AID_INSERT_B_HTML%}',
		]
		txt = util.Template('match-approved-email.txt').content
		self._check_expected_placeholders(txt, placeholders_txt)
		txt = util.Template('match-approved-email.html').content
		self._check_expected_placeholders(txt, placeholders_html)
Exemplo n.º 10
0
	def confirm_offer(self, secret):
		offer = entities.Offer.by_secret(secret)
		if offer is None:
			return None

		# caller knows the secret (which we emailed)
		# => caller received email
		# => email address is valid
		# caller clicked on link we emailed
		# => offer is confirmed
		# => mark it as confirmed in db, and try to find a match for it.

		was_confirmed = offer.confirmed

		if not was_confirmed:
			with self._database.connect() as db:
				offer.confirm(db)
				eventlog.confirmed_offer(db, offer)

		replacements = {
			'{%CHARITY%}': offer.charity.name,
			'{%CURRENCY%}': offer.country.currency.iso,
			'{%AMOUNT%}': offer.amount,
			'{%MIN_AMOUNT%}': offer.min_amount,
			'{%COUNTRY%}': offer.country.name
		}

		self._mail.send(
			util.Template('email-subjects.json').json('post-confirmed-email'),
			util.Template('post-confirmed-email.txt').replace(replacements).content,
			html=util.Template('post-confirmed-email.html').replace(replacements).content,
			to=self._config.contact_message_receivers['to']
		)

		return {
			'was_confirmed': was_confirmed,
			'name': offer.name,
			'currency': offer.country.currency.iso,
			'amount': offer.amount,
			'min_amount': offer.min_amount,
			'charity': offer.charity.name,
			'created_ts': offer.created_ts.isoformat(' '),
			'expires_ts': offer.expires_ts.isoformat(' '),
		}
Exemplo n.º 11
0
	def test_contact_email(self):
		placeholders = [
			'{%IP_ADDRESS%}',
			'{%COUNTRY%}',
			'{%NAME%}',
			'{%EMAIL%}',
			'{%MESSAGE%}',
		]
		txt = util.Template('contact-email.txt').content
		self._check_expected_placeholders(txt, placeholders)
Exemplo n.º 12
0
	def test_errors_and_warnings(self):
		data = util.Template('errors-and-warnings.json').json()
		self.assertTrue('bad amount' in data)
		self.assertTrue('bad captcha' in data)
		self.assertTrue('bad email address' in data)
		self.assertTrue('bad expiration date' in data)
		self.assertTrue('bad min_amount' in data)
		self.assertTrue('charity not found' in data)
		self.assertTrue('country not found' in data)
		self.assertTrue('match not found' in data)
		self.assertTrue('no name provided' in data)
Exemplo n.º 13
0
	def get_page(self, name):
		content = util.Template(name).content

		# This acts as a cache breaker -- just increment
		# self.STATIC_VERSION whenever a static file has changed,
		# so the client will know to re-request it from the server.
		# The only exception are files referenced in style.css,
		# which must be handled manually.
		content = re.sub('src="/static/(.*?)"', lambda m: 'src="/static/%s?v=%s"' % (m.group(1), self.STATIC_VERSION), content)
		content = re.sub('href="/static/(.*?)"', lambda m: 'href="/static/%s?v=%s"' % (m.group(1), self.STATIC_VERSION), content)

		return content
Exemplo n.º 14
0
    def _validate_offer(self, name, country, amount, min_amount, charity,
                        email, expiration):
        errors = util.Template('errors-and-warnings.json')

        name = name.strip()
        if not name:
            raise DonationException(errors.json('no name provided'))

        country = entities.Country.by_id(country)
        if country is None:
            raise DonationException(errors.json('country not found'))

        amount = self._int(amount, errors.json('bad amount'))
        if amount < 0:
            raise DonationException(errors.json('bad amount'))

        min_amount = self._int(min_amount, errors.json('bad min_amount'))
        if min_amount < 0:
            raise DonationException(errors.json('bad min_amount'))

        if min_amount > amount:
            raise DonationException(errors.json('min_amount_larger'))

        min_allowed_amount = self._currency.convert(
            country.min_donation_amount, country.min_donation_currency,
            country.currency)

        if min_amount < min_allowed_amount:
            raise DonationException(
                errors.json('min_amount_too_small') %
                (country.min_donation_amount,
                 country.min_donation_currency.iso))

        charity = entities.Charity.by_id(charity)
        if charity is None:
            raise DonationException(errors.json('charity not found'))

        email = email.strip()
        if not re.fullmatch(r'.+?@.+\..+', email):
            raise DonationException(errors.json('bad email address'))

        expires_ts = '%04i-%02i-%02i' % (
            self._int(expiration['year'], errors.json('bad expiration date')),
            self._int(expiration['month'], errors.json('bad expiration date')),
            self._int(expiration['day'], errors.json('bad expiration date')),
        )
        try:
            expires_ts = datetime.datetime.strptime(expires_ts, '%Y-%m-%d')
        except ValueError:
            raise DonationException(errors.json('bad expiration date'))

        return name, country, amount, min_amount, charity, email, expires_ts
Exemplo n.º 15
0
    def decline_match(self, secret, feedback):
        match, old_offer, new_offer, my_offer, other_offer = self._get_match_and_offers(
            secret)

        if match is None:
            # this error is shown directly to the user, don't put any sensitive details in it!
            raise DonationException(
                util.Template('errors-and-warnings.json').json(
                    'match not found'))

        with self._database.connect() as db:
            query = '''
				do $$ begin
					IF NOT EXISTS (SELECT * FROM declined_matches WHERE new_offer_id=%(id_old)s AND old_offer_id=%(id_new)s) THEN
						INSERT INTO declined_matches (new_offer_id, old_offer_id)
						VALUES (%(id_old)s, %(id_new)s);
					END IF;
				end $$;
			'''
            db.write(query, id_old=old_offer.id, id_new=new_offer.id)
            match.delete(db)
            my_offer.suspend(db)
            eventlog.declined_match(db, match, my_offer, feedback)

            replacements = {
                '{%NAME%}': my_offer.name,
                '{%OFFER_SECRET%}': my_offer.secret,
            }
            self._mail.send(
                util.Template('email-subjects.json').json(
                    'match-decliner-email'),
                util.Template('match-decliner-email.txt').replace(
                    replacements).content,
                html=util.Template('match-decliner-email.html').replace(
                    replacements).content,
                to=my_offer.email)

            email_subject = 'match-declined-email'
            if other_offer == old_offer and match.old_agrees:
                email_subject = 'match-approved-declined-email'
            elif other_offer == new_offer and match.new_agrees:
                email_subject = 'match-approved-declined-email'

            replacements = {
                '{%NAME%}': other_offer.name,
                '{%OFFER_SECRET%}': other_offer.secret,
            }
            self._mail.send(
                util.Template('email-subjects.json').json(email_subject),
                util.Template('match-declined-email.txt').replace(
                    replacements).content,
                html=util.Template('match-declined-email.html').replace(
                    replacements).content,
                to=other_offer.email)
Exemplo n.º 16
0
	def approve_match(self, secret):
		match, old_offer, new_offer, my_offer, _ = self._get_match_and_offers(secret)

		if match is None:
			# this error is shown directly to the user, don't put any sensitive details in it!
			raise DonationException(
				util.Template('errors-and-warnings.json').json('match not found')
			)

		with self._database.connect() as db:
			if my_offer == old_offer:
				match.agree_old(db)
				eventlog.approved_match(db, match, my_offer)
			elif my_offer == new_offer:
				match.agree_new(db)
				eventlog.approved_match(db, match, my_offer)

			if match.old_agrees and match.new_agrees:
				self._send_mail_about_approved_match(match, old_offer, new_offer, db)
Exemplo n.º 17
0
	def _send_feedback_email(self, match, db):
		new_offer = entities.Offer.by_id(match.new_offer_id)
		old_offer = entities.Offer.by_id(match.old_offer_id)

		new_actual_amount, old_actual_amount = self._get_actual_amounts(match, new_offer, old_offer, db)

		new_replacements = {
			'{%NAME%}': new_offer.name,
			'{%NAME_OTHER%}': old_offer.name,
			'{%AMOUNT%}': new_actual_amount,
			'{%CURRENCY%}': new_offer.country.currency.iso,
			'{%CHARITY%}': new_offer.charity.name,
			'{%AMOUNT_OTHER%}': old_actual_amount,
			'{%CURRENCY_OTHER%}': old_offer.country.currency.iso,
			'{%CHARITY_OTHER%}': old_offer.charity.name,
			'{%OFFER_SECRET%}': urllib.parse.quote(new_offer.secret)
		}

		old_replacements = {
			'{%NAME%}': old_offer.name,
			'{%NAME_OTHER%}': new_offer.name,
			'{%AMOUNT%}':old_actual_amount,
			'{%CURRENCY%}': old_offer.country.currency.iso,
			'{%CHARITY%}': old_offer.charity.name,
			'{%AMOUNT_OTHER%}': new_actual_amount,
			'{%CURRENCY_OTHER%}': new_offer.country.currency.iso,
			'{%CHARITY_OTHER%}': new_offer.charity.name,
			'{%OFFER_SECRET%}': urllib.parse.quote(old_offer.secret)
		}

		self._mail.send(
			util.Template('email-subjects.json').json('feedback-email'),
			util.Template('feedback-email.txt').replace(new_replacements).content,
			html=util.Template('feedback-email.html').replace(new_replacements).content,
			to=new_offer.email)

		self._mail.send(
			util.Template('email-subjects.json').json('feedback-email'),
			util.Template('feedback-email.txt').replace(old_replacements).content,
			html=util.Template('feedback-email.html').replace(old_replacements).content,
			to=old_offer.email)
Exemplo n.º 18
0
	def _send_mail_about_approved_match(self, match, offer_a, offer_b, db):

		actual_amount_a, actual_amount_b = self._get_actual_amounts(match, offer_a, offer_b, db)
		to_charity_a = actual_amount_a * offer_a.country.gift_aid_multiplier
		to_charity_b = actual_amount_b * offer_b.country.gift_aid_multiplier

		tmp = entities.CharityInCountry.by_charity_and_country_id(
			offer_b.charity.id,
			offer_a.country.id)
		if tmp is not None:
			instructions_a = tmp.instructions
		else:
			instructions_a = 'Sorry, there are no instructions available (yet).'

		tmp = entities.CharityInCountry.by_charity_and_country_id(
			offer_a.charity.id,
			offer_b.country.id)
		if tmp is not None:
			instructions_b = tmp.instructions
		else:
			instructions_b = 'Sorry, there are no instructions available (yet).'

		gift_aid_insert_a_txt, gift_aid_insert_a_html = self._get_gift_aid_insert(offer_a, to_charity_a, offer_b.charity.name)
		gift_aid_insert_b_txt, gift_aid_insert_b_html = self._get_gift_aid_insert(offer_b, to_charity_b, offer_a.charity.name)

		currency_a_as_b = self._currency.convert(
			1000,
			offer_a.country.currency.iso,
			offer_b.country.currency.iso) / 1000.0

		replacements = {
			'{%NAME_A%}': offer_a.name,
			'{%COUNTRY_A%}': offer_a.country.name,
			'{%CHARITY_A%}': offer_a.charity.name,
			'{%ACTUAL_AMOUNT_A%}': actual_amount_a, # the amount A donates
			'{%CURRENCY_A%}': offer_a.country.currency.iso,
			'{%EMAIL_A%}': offer_a.email,
			'{%INSTRUCTIONS_A%}': instructions_a,
			'{%TO_CHARITY_A%}': to_charity_a, # the amount received from A's donation
			'{%GIFT_AID_INSERT_A_TXT%}': gift_aid_insert_a_txt,
			'{%GIFT_AID_INSERT_A_HTML%}': gift_aid_insert_a_html,
			'{%ONE_CURRENCY_A_AS_B%}': currency_a_as_b,
			'{%NAME_B%}': offer_b.name,
			'{%COUNTRY_B%}': offer_b.country.name,
			'{%CHARITY_B%}': offer_b.charity.name,
			'{%ACTUAL_AMOUNT_B%}': actual_amount_b,
			'{%CURRENCY_B%}': offer_b.country.currency.iso,
			'{%EMAIL_B%}': offer_b.email,
			'{%INSTRUCTIONS_B%}': instructions_b,
			'{%TO_CHARITY_B%}': to_charity_b,
			'{%GIFT_AID_INSERT_B_TXT%}': gift_aid_insert_b_txt,
			'{%GIFT_AID_INSERT_B_HTML%}': gift_aid_insert_b_html,
		}

		logging.info('Sending deal email to %s and %s.', offer_a.email, offer_b.email)

		self._mail.send(
			util.Template('email-subjects.json').json('match-approved-email'),
			util.Template('match-approved-email.txt').replace(replacements).content,
			html=util.Template('match-approved-email.html').replace(replacements).content,
			to=[offer_a.email, offer_b.email]
		)
Exemplo n.º 19
0
	def test_email_subjects(self):
		data = util.Template('email-subjects.json').json()
		self.assertTrue('match-declined-email' in data)
		self.assertTrue('match-approved-declined-email' in data)
		self.assertTrue('match-decliner-email' in data)
		self.assertTrue('new-post-email' in data)
Exemplo n.º 20
0
	def _send_mail_about_unconfirmed_matches(self, match):
		new_offer = entities.Offer.by_id(match.new_offer_id)
		old_offer = entities.Offer.by_id(match.old_offer_id)

		new_replacements = {
			'{%NAME%}': new_offer.name,
			'{%OFFER_SECRET%}': new_offer.secret,
			'{%ARGS%}': '#%s' % urllib.parse.quote(json.dumps({
				'name': new_offer.name,
				'country': new_offer.country_id,
				'amount': new_offer.amount,
				'min_amount': new_offer.min_amount,
				'charity': new_offer.charity_id,
				'email': new_offer.email,
				'expires': {
					'day': new_offer.expires_ts.day,
					'month': new_offer.expires_ts.month,
					'year': new_offer.expires_ts.year,
				}
			}))
		}

		old_replacements = {
			'{%NAME%}': old_offer.name,
			'{%OFFER_SECRET%}': old_offer.secret,
			'{%ARGS%}': '#%s' % urllib.parse.quote(json.dumps({
				'name': old_offer.name,
				'country': old_offer.country_id,
				'amount': old_offer.amount,
				'min_amount': old_offer.min_amount,
				'charity': old_offer.charity_id,
				'email': old_offer.email,
				'expires': {
					'day': old_offer.expires_ts.day,
					'month': old_offer.expires_ts.month,
					'year': old_offer.expires_ts.year,
				}
			}))
		}

		#TODO: needs args applied to a new offer rather than reconfirming old offer

		if (match.new_agrees == True):
			self._mail.send(
				util.Template('email-subjects.json').json('match-unconfirmed-email'),
				util.Template('match-unconfirmed-email.txt').replace(new_replacements).content,
				html=util.Template('match-unconfirmed-email.html').replace(new_replacements).content,
				to=new_offer.email)
		else:
			self._mail.send(
				util.Template('email-subjects.json').json('match-unconfirmer-email'),
				util.Template('match-unconfirmer-email.txt').replace(new_replacements).content,
				html=util.Template('match-unconfirmer-email.html').replace(new_replacements).content,
				to=new_offer.email)

		if (match.old_agrees == True):
			self._mail.send(
				util.Template('email-subjects.json').json('match-unconfirmed-email'),
				util.Template('match-unconfirmed-email.txt').replace(old_replacements).content,
				html=util.Template('match-unconfirmed-email.html').replace(old_replacements).content,
				to=old_offer.email)
		else:
			self._mail.send(
				util.Template('email-subjects.json').json('match-unconfirmer-email'),
				util.Template('match-unconfirmer-email.txt').replace(old_replacements).content,
				html=util.Template('match-unconfirmer-email.html').replace(old_replacements).content,
				to=old_offer.email)