[10.0][IMP] mail_tracking_mailgun: add partner mail checks
This commit is contained in:
parent
3e8273581b
commit
3ca3ee4e49
@ -29,9 +29,16 @@ You must configure Mailgun webhooks in order to receive mail events:
|
||||
Replace '<your_domain>' with your Odoo install domain name
|
||||
and '<your_database>' with your database name.
|
||||
|
||||
In order to validate Mailgun webhooks you have to save Mailgun api_key in
|
||||
a system parameter named 'mailgun.apikey'. You can find Mailgun api_key in your
|
||||
validated sending domain.
|
||||
In order to validate Mailgun webhooks you have to configure the following system
|
||||
parameters:
|
||||
|
||||
- `mailgun.apikey`: You can find Mailgun api_key in your validated sending
|
||||
domain.
|
||||
- `mailgun.api_url`: It should be fine as it is, but it could change in the
|
||||
future.
|
||||
- `mailgun.validation_key`: If you want to be able to check mail address
|
||||
validity you must config this parameter with your account Public Validation
|
||||
Key.
|
||||
|
||||
Usage
|
||||
=====
|
||||
@ -40,6 +47,17 @@ In your mail tracking status screens (explained on module *mail_tracking*), you
|
||||
see a more accurate information, like the 'Received' or 'Bounced' status, which are
|
||||
not usually detected by normal SMTP servers.
|
||||
|
||||
It's also possible to make some checks to the partner's email addresses against the Mailgun API:
|
||||
|
||||
- Check if the partner's email is in Mailgun's bounced list.
|
||||
- Check the validity of the partner's mailbox.
|
||||
- Force the partner's email into Mailgun's bounced list or delete from it.
|
||||
|
||||
It's also possible to manually check a message mailgun tracking when the webhook
|
||||
couldn't be captured. For that, go to that message tracking form, press the
|
||||
button *Check Mailgun*. It's important to note that tracking events have quite a
|
||||
short lifespan, so after 24h they won't be recoverable.
|
||||
|
||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||
:alt: Try me on Runbot
|
||||
:target: https://runbot.odoo-community.org/runbot/205/9.0
|
||||
@ -70,6 +88,8 @@ Contributors
|
||||
|
||||
* Antonio Espinosa <antonio.espinosa@tecnativa.com>
|
||||
* Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||
* Pedro M. Baeza <pedro.baeza@tecnativa.com>
|
||||
* David Vidal <david.vidal@tecnativa.com>
|
||||
* Rafael Blasco <rafael.blasco@tecnativa.com>
|
||||
|
||||
Maintainer
|
||||
|
@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import models
|
||||
|
@ -1,10 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2016 Tecnativa - Carlos Dauden
|
||||
# Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
# Copyright 2017 Tecnativa - David Vidal
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
{
|
||||
"name": "Mail tracking for Mailgun",
|
||||
"summary": "Mail tracking and Mailgun webhooks integration",
|
||||
"version": "10.0.1.0.0",
|
||||
"version": "10.0.1.1.0",
|
||||
"category": "Social Network",
|
||||
"website": "https://odoo-community.org/",
|
||||
"author": "Tecnativa, "
|
||||
@ -15,4 +18,8 @@
|
||||
"depends": [
|
||||
"mail_tracking",
|
||||
],
|
||||
"data": [
|
||||
"views/res_partner.xml",
|
||||
"views/mail_tracking_email.xml",
|
||||
]
|
||||
}
|
||||
|
@ -8,17 +8,138 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 8.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-09-02 02:43+0000\n"
|
||||
"PO-Revision-Date: 2016-09-02 02:43+0000\n"
|
||||
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2016\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n"
|
||||
"POT-Creation-Date: 2017-11-22 09:11+0000\n"
|
||||
"PO-Revision-Date: 2017-11-22 09:11+0000\n"
|
||||
"Last-Translator: <david.vidal@tecnativa.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/res_partner.py:82
|
||||
#, python-format
|
||||
msgid "%s couldn't be verified. Either the request couln't be completed or the mailbox provider doesn't support email verification"
|
||||
msgstr "%s no ha podido ser verificado. Puede que la petición no se haya completado o que el buzón no soporta validación de correo electrónico"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/res_partner.py:76
|
||||
#, python-format
|
||||
msgid "%s failed the mailbox verification. Please check it in order to avoid sending issues"
|
||||
msgstr "%s no ha pasado la validación de buzón. Compruébela para prevenir problemas con los envíos"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/res_partner.py:69
|
||||
#, python-format
|
||||
msgid "%s is not a valid email address. Please check it in order to avoid sending issues"
|
||||
msgstr "%s no es una dirección válida de correo electrónico. Compruébela para prevenir problemas con los envíos"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/mail_tracking_email.py:75
|
||||
#, python-format
|
||||
msgid "A Mailgun domain value is needed!"
|
||||
msgstr "¡Se necesita un valor de dominio para Mailgun!\""
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.ui.view,arch_db:mail_tracking_mailgun.view_partner_form_mailgun
|
||||
msgid "Check Mailgun"
|
||||
msgstr "Comprobar Mailgun"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.ui.view,arch_db:mail_tracking_mailgun.view_partner_form_mailgun
|
||||
msgid "Check email validity"
|
||||
msgstr "Comprobar validez de email"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/mail_tracking_email.py:236
|
||||
#, python-format
|
||||
msgid "Couldn't retrieve Mailgun information"
|
||||
msgstr "No se ha podido obtener información desde Mailgun"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/res_partner.py:30
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Email has been bounced: %s\n"
|
||||
"Reason: %s\n"
|
||||
"Event: %s"
|
||||
msgstr ""
|
||||
"El correo ha sido rebotado: %s\n"
|
||||
"Razón: %s\n"
|
||||
"Evento: %s"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/res_partner.py:56
|
||||
#, python-format
|
||||
msgid "Error %s trying to check mailof connection"
|
||||
msgstr "Error %s al intentar comprobar el correo electrónicodeconexión"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/mail_tracking_email.py:240
|
||||
#, python-format
|
||||
msgid "Event information not longer stored"
|
||||
msgstr "La información del evento ha caducado"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.model,name:mail_tracking_mailgun.model_mail_tracking_email
|
||||
msgid "MailTracking email"
|
||||
msgstr "MailTracking email"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.model,name:mail_tracking_mailgun.model_mail_tracking_event
|
||||
msgid "MailTracking event"
|
||||
msgstr "MailTracking event"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.ui.view,arch_db:mail_tracking_mailgun.view_partner_form_mailgun
|
||||
msgid "Mailgun"
|
||||
msgstr "Mailgun"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/res_partner.py:62
|
||||
#, python-format
|
||||
msgid "Mailgun Error. Mailbox verification value wasn't returned"
|
||||
msgstr "Error de Mailgun. No se ha devuelto el valor de verificación de buzón"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.model.fields,field_description:mail_tracking_mailgun.field_mail_tracking_event_mailgun_id
|
||||
msgid "Mailgun Event ID"
|
||||
msgstr "Mailgun Event ID"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.model,name:mail_tracking_mailgun.model_res_partner
|
||||
msgid "Partner"
|
||||
msgstr "Empresa"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.ui.view,arch_db:mail_tracking_mailgun.mailgun_manual_check
|
||||
msgid "Re-sync Mailgun"
|
||||
msgstr "Resincronizar Mailgun"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.ui.view,arch_db:mail_tracking_mailgun.view_partner_form_mailgun
|
||||
msgid "Set Bounced"
|
||||
msgstr "Marcar como rebotado"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/mail_tracking_email.py:70
|
||||
#, python-format
|
||||
msgid "There is no Mailgun API key!"
|
||||
msgstr "¡No hay clave de API de Mailgun!"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.ui.view,arch_db:mail_tracking_mailgun.view_partner_form_mailgun
|
||||
msgid "Unset Bounced"
|
||||
msgstr "Desmarcar como rebotado"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: code:addons/mail_tracking_mailgun/models/res_partner.py:46
|
||||
#, python-format
|
||||
msgid "You need to configure mailgun.validation_key in order to be able to check mails validity"
|
||||
msgstr "Necesitas configurar mailgun.validation_key para poder comprobar la validez de direcciones de correo"
|
||||
|
||||
#. module: mail_tracking_mailgun
|
||||
#: model:ir.model,name:mail_tracking_mailgun.model_ir_mail_server
|
||||
msgid "ir.mail_server"
|
||||
msgstr "ir.mail_server"
|
||||
|
@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import ir_mail_server
|
||||
from . import mail_tracking_email
|
||||
from . import mail_tracking_event
|
||||
from . import res_partner
|
||||
|
@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import json
|
||||
|
@ -1,11 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2017 Tecnativa - David Vidal
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from odoo import models, api, fields
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
@ -40,6 +44,7 @@ class MailTrackingEmail(models.Model):
|
||||
'complained': 'spam',
|
||||
'bounced': 'hard_bounce',
|
||||
'dropped': 'reject',
|
||||
'accepted': 'sent',
|
||||
}
|
||||
|
||||
def _mailgun_event_type_verify(self, event):
|
||||
@ -58,6 +63,19 @@ class MailTrackingEmail(models.Model):
|
||||
msg='{}{}'.format(str(timestamp), str(token)),
|
||||
digestmod=hashlib.sha256).hexdigest()
|
||||
|
||||
def _mailgun_values(self):
|
||||
icp = self.env['ir.config_parameter']
|
||||
api_key = icp.get_param('mailgun.apikey')
|
||||
if not api_key:
|
||||
raise ValidationError(_('There is no Mailgun API key!'))
|
||||
api_url = icp.get_param(
|
||||
'mailgun.api_url', 'https://api.mailgun.net/v3')
|
||||
domain = icp.get_param('mail.catchall.domain')
|
||||
if not domain:
|
||||
raise ValidationError(_('A Mailgun domain value is needed!'))
|
||||
validation_key = icp.get_param('mailgun.validation_key')
|
||||
return api_key, api_url, domain, validation_key
|
||||
|
||||
def _mailgun_signature_verify(self, event):
|
||||
event = event or {}
|
||||
api_key = self.env['ir.config_parameter'].get_param('mailgun.apikey')
|
||||
@ -104,6 +122,7 @@ class MailTrackingEmail(models.Model):
|
||||
'timestamp': ts,
|
||||
'time': fields.Datetime.to_string(dt),
|
||||
'date': fields.Date.to_string(dt),
|
||||
'mailgun_id': event.get('id', False)
|
||||
})
|
||||
# Common field mapping
|
||||
mapping = {
|
||||
@ -192,3 +211,38 @@ class MailTrackingEmail(models.Model):
|
||||
else:
|
||||
_logger.info("Mailgun: event process '%s'", res)
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def action_manual_check_mailgun(self):
|
||||
"""
|
||||
Manual check against Mailgun API
|
||||
API Documentation:
|
||||
https://documentation.mailgun.com/en/latest/api-events.html
|
||||
"""
|
||||
api_key, api_url, domain, validation_key = self._mailgun_values()
|
||||
for tracking in self:
|
||||
message_id = tracking.mail_message_id.message_id.replace(
|
||||
"<", "").replace(">", "")
|
||||
res = requests.get(
|
||||
'%s/%s/events' % (api_url, domain),
|
||||
auth=("api", api_key),
|
||||
params={
|
||||
"begin": tracking.timestamp,
|
||||
"ascending": "yes",
|
||||
"message-id": message_id,
|
||||
}
|
||||
)
|
||||
if not res or res.status_code != 200:
|
||||
raise ValidationError(_(
|
||||
"Couldn't retrieve Mailgun information"))
|
||||
content = json.loads(res.content, res.apparent_encoding)
|
||||
if "items" not in content:
|
||||
raise ValidationError(_("Event information not longer stored"))
|
||||
for item in content["items"]:
|
||||
if not self.env['mail.tracking.event'].search(
|
||||
[('mailgun_id', '=', item["id"])]):
|
||||
mapped_event_type = self._mailgun_event_type_mapping.get(
|
||||
item["event"]) or False
|
||||
metadata = self._mailgun_metadata(
|
||||
mapped_event_type, item, {})
|
||||
tracking.event_create(mapped_event_type, metadata)
|
||||
|
21
mail_tracking_mailgun/models/mail_tracking_event.py
Normal file
21
mail_tracking_mailgun/models/mail_tracking_event.py
Normal file
@ -0,0 +1,21 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Tecnativa - David Vidal
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from openerp import models, fields
|
||||
|
||||
|
||||
class MailTrackingEvent(models.Model):
|
||||
_inherit = "mail.tracking.event"
|
||||
|
||||
mailgun_id = fields.Char(
|
||||
string="Mailgun Event ID",
|
||||
copy="False",
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
def _process_data(self, tracking_email, metadata, event_type, state):
|
||||
res = super(MailTrackingEvent, self)._process_data(
|
||||
tracking_email, metadata, event_type, state)
|
||||
res.update({'mailgun_id': metadata.get('mailgun_id', False)})
|
||||
return res
|
135
mail_tracking_mailgun/models/res_partner.py
Normal file
135
mail_tracking_mailgun/models/res_partner.py
Normal file
@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2016 Tecnativa - Carlos Dauden
|
||||
# Copyright 2017 Tecnativa - Pedro M. Baeza
|
||||
# Copyright 2017 Tecnativa - David Vidal
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import requests
|
||||
import json
|
||||
|
||||
from openerp import _, api, models
|
||||
from openerp.exceptions import UserError
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
@api.multi
|
||||
def email_bounced_set(self, tracking_emails, reason, event=None):
|
||||
res = super(ResPartner, self).email_bounced_set(
|
||||
tracking_emails, reason, event=event)
|
||||
self._email_bounced_set(reason, event)
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def _email_bounced_set(self, reason, event):
|
||||
for partner in self:
|
||||
if not partner.email:
|
||||
continue
|
||||
body = _('Email has been bounced: %s\n'
|
||||
'Reason: %s\n'
|
||||
'Event: %s') % (partner.email, reason,
|
||||
event['Message-Id'] or '')
|
||||
partner.message_post(body=body)
|
||||
|
||||
@api.multi
|
||||
def check_email_validity(self):
|
||||
"""
|
||||
Checks mailbox validity with Mailgun's API
|
||||
API documentation:
|
||||
https://documentation.mailgun.com/en/latest/api-email-validation.html
|
||||
"""
|
||||
api_key, api_url, domain, validation_key = self.env[
|
||||
'mail.tracking.email']._mailgun_values()
|
||||
if not validation_key:
|
||||
raise UserError(_('You need to configure mailgun.validation_key'
|
||||
' in order to be able to check mails validity'))
|
||||
for partner in self:
|
||||
res = requests.get(
|
||||
"%s/address/validate" % api_url,
|
||||
auth=("api", validation_key), params={
|
||||
"address": partner.email,
|
||||
"mailbox_verification": True,
|
||||
})
|
||||
if not res or res.status_code != 200:
|
||||
raise UserError(_(
|
||||
'Error %s trying to '
|
||||
'check mail' % res.status_code or 'of connection'))
|
||||
content = json.loads(res.content, res.apparent_encoding)
|
||||
if 'mailbox_verification' not in content:
|
||||
raise UserError(
|
||||
_("Mailgun Error. Mailbox verification value wasn't"
|
||||
" returned"))
|
||||
# Not a valid address: API sets 'is_valid' as False
|
||||
# and 'mailbox_verification' as None
|
||||
if not content['is_valid']:
|
||||
partner.email_bounced = True
|
||||
raise UserError(
|
||||
_('%s is not a valid email address. Please check it '
|
||||
'in order to avoid sending issues') % (partner.email))
|
||||
# If the mailbox is not valid API returns 'mailbox_verification'
|
||||
# as a string with value 'false'
|
||||
if content['mailbox_verification'] == 'false':
|
||||
partner.email_bounced = True
|
||||
raise UserError(
|
||||
_('%s failed the mailbox verification. Please check it '
|
||||
'in order to avoid sending issues') % (partner.email))
|
||||
# If Mailgun can't complete the validation request the API returns
|
||||
# 'mailbox_verification' as a string set to 'unknown'
|
||||
if content['mailbox_verification'] == 'unknown':
|
||||
raise UserError(
|
||||
_("%s couldn't be verified. Either the request couln't be "
|
||||
"completed or the mailbox provider doesn't support "
|
||||
"email verification") % (partner.email))
|
||||
|
||||
@api.multi
|
||||
def check_email_bounced(self):
|
||||
"""
|
||||
Checks if the partner's email is in Mailgun's bounces list
|
||||
API documentation:
|
||||
https://documentation.mailgun.com/en/latest/api-suppressions.html
|
||||
"""
|
||||
api_key, api_url, domain, validation_key = self.env[
|
||||
'mail.tracking.email']._mailgun_values()
|
||||
for partner in self:
|
||||
res = requests.get(
|
||||
'%s/%s/bounces/%s' % (api_url, domain, partner.email),
|
||||
auth=("api", api_key))
|
||||
if res.status_code == 200 and not partner.email_bounced:
|
||||
partner.email_bounced = True
|
||||
elif res.status_code == 404 and partner.email_bounced:
|
||||
partner.email_bounced = False
|
||||
|
||||
@api.multi
|
||||
def force_set_bounced(self):
|
||||
"""
|
||||
Forces partner's email into Mailgun's bounces list
|
||||
API documentation:
|
||||
https://documentation.mailgun.com/en/latest/api-suppressions.html
|
||||
"""
|
||||
api_key, api_url, domain, validation_key = self.env[
|
||||
'mail.tracking.email']._mailgun_values()
|
||||
for partner in self:
|
||||
res = requests.post(
|
||||
'%s/%s/bounces' % (api_url, domain),
|
||||
auth=("api", api_key),
|
||||
data={'address': partner.email})
|
||||
partner.email_bounced = (
|
||||
res.status_code == 200 and not partner.email_bounced)
|
||||
|
||||
@api.multi
|
||||
def force_unset_bounced(self):
|
||||
"""
|
||||
Forces partner's email deletion from Mailgun's bounces list
|
||||
API documentation:
|
||||
https://documentation.mailgun.com/en/latest/api-suppressions.html
|
||||
"""
|
||||
api_key, api_url, domain, validation_key = self.env[
|
||||
'mail.tracking.email']._mailgun_values()
|
||||
for partner in self:
|
||||
res = requests.delete(
|
||||
'%s/%s/bounces/%s' % (api_url, domain, partner.email),
|
||||
auth=("api", api_key))
|
||||
if res.status_code in (200, 404) and partner.email_bounced:
|
||||
partner.email_bounced = False
|
@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import test_mailgun
|
||||
|
@ -1,9 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Antonio Espinosa - <antonio.espinosa@tecnativa.com>
|
||||
# Copyright 2016 Tecnativa - Antonio Espinosa
|
||||
# Copyright 2017 Tecnativa - David Vidal
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo.tools import mute_logger
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
import mock
|
||||
import json
|
||||
|
||||
_packagepath = 'odoo.addons.mail_tracking_mailgun'
|
||||
|
||||
|
||||
class TestMailgun(TransactionCase):
|
||||
@ -26,12 +32,17 @@ class TestMailgun(TransactionCase):
|
||||
self.recipient = u'to@example.com'
|
||||
self.mail, self.tracking_email = self.mail_send()
|
||||
self.api_key = u'key-12345678901234567890123456789012'
|
||||
self.domain = u'example.com'
|
||||
self.token = u'f1349299097a51b9a7d886fcb5c2735b426ba200ada6e9e149'
|
||||
self.timestamp = u'1471021089'
|
||||
self.signature = ('4fb6d4dbbe10ce5d620265dcd7a3c0b8'
|
||||
'ca0dede1433103891bc1ae4086e9d5b2')
|
||||
self.env['ir.config_parameter'].set_param(
|
||||
'mailgun.apikey', self.api_key)
|
||||
self.env['ir.config_parameter'].set_param(
|
||||
'mail.catchall.domain', self.domain)
|
||||
self.env['ir.config_parameter'].set_param(
|
||||
'mailgun.validation_key', self.api_key)
|
||||
self.event = {
|
||||
'Message-Id': u'<xxx.xxx.xxx-openerp-xxx-res.partner@test_db>',
|
||||
'X-Mailgun-Sid': u'WyIwNjgxZSIsICJ0b0BleGFtcGxlLmNvbSIsICI3MG'
|
||||
@ -51,6 +62,26 @@ class TestMailgun(TransactionCase):
|
||||
'os_family': False,
|
||||
'ua_family': False,
|
||||
}
|
||||
self.partner = self.env['res.partner'].create({
|
||||
'name': 'Mr. Odoo',
|
||||
'email': 'mrodoo@example.com',
|
||||
})
|
||||
self.response = {
|
||||
"items": [{
|
||||
"log-level": "info",
|
||||
"id": "oXAVv5URCF-dKv8c6Sa7T",
|
||||
"timestamp": 1509119329.0,
|
||||
"message": {
|
||||
"headers": {
|
||||
"to": "test@test.com",
|
||||
"message-id": "test-id@f187c54734e8",
|
||||
"from": "Mr. Odoo <mrodoo@odoo.com>",
|
||||
"subject": "This is a test"
|
||||
},
|
||||
},
|
||||
"event": "delivered"
|
||||
}]
|
||||
}
|
||||
|
||||
def event_search(self, event_type):
|
||||
event = self.env['mail.tracking.event'].search([
|
||||
@ -63,6 +94,14 @@ class TestMailgun(TransactionCase):
|
||||
def test_no_api_key(self):
|
||||
self.env['ir.config_parameter'].set_param('mailgun.apikey', '')
|
||||
self.test_event_delivered()
|
||||
with self.assertRaises(ValidationError):
|
||||
self.env['mail.tracking.email']._mailgun_values()
|
||||
|
||||
def test_no_domain(self):
|
||||
self.env['ir.config_parameter'].set_param('mail.catchall.domain', '')
|
||||
self.test_event_delivered()
|
||||
with self.assertRaises(ValidationError):
|
||||
self.env['mail.tracking.email']._mailgun_values()
|
||||
|
||||
@mute_logger('odoo.addons.mail_tracking_mailgun.models'
|
||||
'.mail_tracking_email')
|
||||
@ -288,3 +327,93 @@ class TestMailgun(TransactionCase):
|
||||
self.assertEqual(event.error_type, reason)
|
||||
self.assertEqual(event.error_description, code)
|
||||
self.assertEqual(event.error_details, description)
|
||||
|
||||
@mock.patch(_packagepath + '.models.res_partner.requests')
|
||||
def test_email_validity(self, mock_request):
|
||||
self.partner.email_bounced = False
|
||||
self.partner.email = 'info@tecnativa.com'
|
||||
mock_request.get.return_value.apparent_encoding = 'ascii'
|
||||
mock_request.get.return_value.status_code = 200
|
||||
mock_request.get.return_value.content = json.dumps({
|
||||
'is_valid': True,
|
||||
'mailbox_verification': 'true',
|
||||
}, ensure_ascii=True)
|
||||
self.partner.check_email_validity()
|
||||
self.assertFalse(self.partner.email_bounced)
|
||||
self.partner.email = 'xoxoxoxo@tecnativa.com'
|
||||
# Not a valid mailbox
|
||||
mock_request.get.return_value.content = json.dumps({
|
||||
'is_valid': True,
|
||||
'mailbox_verification': 'false',
|
||||
}, ensure_ascii=True)
|
||||
with self.assertRaises(UserError):
|
||||
self.partner.check_email_validity()
|
||||
# Not a valid mail address
|
||||
mock_request.get.return_value.content = json.dumps({
|
||||
'is_valid': False,
|
||||
'mailbox_verification': 'false',
|
||||
}, ensure_ascii=True)
|
||||
with self.assertRaises(UserError):
|
||||
self.partner.check_email_validity()
|
||||
# Unable to fully validate
|
||||
mock_request.get.return_value.content = json.dumps({
|
||||
'is_valid': True,
|
||||
'mailbox_verification': 'unknown',
|
||||
}, ensure_ascii=True)
|
||||
with self.assertRaises(UserError):
|
||||
self.partner.check_email_validity()
|
||||
self.assertTrue(self.partner.email_bounced)
|
||||
|
||||
@mock.patch(_packagepath + '.models.res_partner.requests')
|
||||
def test_email_validity_exceptions(self, mock_request):
|
||||
mock_request.get.return_value.status_code = 404
|
||||
with self.assertRaises(UserError):
|
||||
self.partner.check_email_validity()
|
||||
self.env['ir.config_parameter'].set_param('mailgun.validation_key', '')
|
||||
with self.assertRaises(UserError):
|
||||
self.partner.check_email_validity()
|
||||
|
||||
@mock.patch(_packagepath + '.models.res_partner.requests')
|
||||
def test_bounced(self, mock_request):
|
||||
self.partner.email_bounced = True
|
||||
mock_request.get.return_value.status_code = 404
|
||||
self.partner.check_email_bounced()
|
||||
self.assertFalse(self.partner.email_bounced)
|
||||
mock_request.get.return_value.status_code = 200
|
||||
self.partner.force_set_bounced()
|
||||
self.partner.check_email_bounced()
|
||||
self.assertTrue(self.partner.email_bounced)
|
||||
mock_request.delete.return_value.status_code = 200
|
||||
self.partner.force_unset_bounced()
|
||||
self.assertFalse(self.partner.email_bounced)
|
||||
|
||||
def test_email_bounced_set(self):
|
||||
message_number = len(self.partner.message_ids) + 1
|
||||
self.partner._email_bounced_set('test_error', self.event)
|
||||
self.assertEqual(len(self.partner.message_ids), message_number)
|
||||
self.partner.email = ""
|
||||
self.partner._email_bounced_set('test_error', self.event)
|
||||
self.assertEqual(len(self.partner.message_ids), message_number)
|
||||
|
||||
@mock.patch(_packagepath + '.models.mail_tracking_email.requests')
|
||||
def test_manual_check(self, mock_request):
|
||||
mock_request.get.return_value.content = json.dumps(self.response,
|
||||
ensure_ascii=True)
|
||||
mock_request.get.return_value.apparent_encoding = 'ascii'
|
||||
mock_request.get.return_value.status_code = 200
|
||||
self.tracking_email.action_manual_check_mailgun()
|
||||
event = self.env['mail.tracking.event'].search(
|
||||
[('mailgun_id', '=', self.response['items'][0]['id'])])
|
||||
self.assertEqual(event.event_type, self.response['items'][0]['event'])
|
||||
|
||||
@mock.patch(_packagepath + '.models.mail_tracking_email.requests')
|
||||
def test_manual_check_exceptions(self, mock_request):
|
||||
mock_request.get.return_value.status_code = 404
|
||||
with self.assertRaises(ValidationError):
|
||||
self.tracking_email.action_manual_check_mailgun()
|
||||
mock_request.get.return_value.status_code = 200
|
||||
mock_request.get.return_value.content = json.dumps('{}',
|
||||
ensure_ascii=True)
|
||||
mock_request.get.return_value.apparent_encoding = 'ascii'
|
||||
with self.assertRaises(ValidationError):
|
||||
self.tracking_email.action_manual_check_mailgun()
|
||||
|
16
mail_tracking_mailgun/views/mail_tracking_email.xml
Normal file
16
mail_tracking_mailgun/views/mail_tracking_email.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="mailgun_manual_check" model="ir.ui.view">
|
||||
<field name="name">Manual Mailgun check</field>
|
||||
<field name="model">mail.tracking.email</field>
|
||||
<field name="inherit_id" ref="mail_tracking.view_mail_tracking_email_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="state" position="before">
|
||||
<button name="action_manual_check_mailgun"
|
||||
type="object" string="Re-sync Mailgun"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
28
mail_tracking_mailgun/views/res_partner.xml
Normal file
28
mail_tracking_mailgun/views/res_partner.xml
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2016 Tecnativa - Pedro M. Baeza
|
||||
Copyright 2016 Carlos Dauden - Tecnativa <carlos.dauden@tecnativa.com>
|
||||
Copyright 2017 Tecnativa <vicent.cubellsn@tecnativa.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
|
||||
<odoo>
|
||||
|
||||
<record id="view_partner_form_mailgun" model="ir.ui.view">
|
||||
<field name="name">Partner Mailgun button</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="mail_tracking.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="email_bounced" position="after">
|
||||
<label for="check_email_bounced" string="Mailgun"
|
||||
attrs="{'invisible': [('email', '=', False)]}"/>
|
||||
<group col="3" name="mailgun_buttons" attrs="{'invisible': [('email', '=', False)]}">
|
||||
<button name="check_email_bounced" type="object" string="Check Mailgun" class="oe_link"/>
|
||||
<button name="check_email_validity" type="object" string="Check email validity" class="oe_link"/>
|
||||
<button name="force_set_bounced" type="object" string="Set Bounced" class="oe_link"
|
||||
attrs="{'invisible': [('email_bounced', '=', True)]}"/>
|
||||
<button name="force_unset_bounced" type="object" string="Unset Bounced" class="oe_link"
|
||||
attrs="{'invisible': [('email_bounced', '=', False)]}"/>
|
||||
</group>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
Loading…
Reference in New Issue
Block a user