@ -0,0 +1,52 @@ |
|||||
|
SendGrid Email API |
||||
|
================== |
||||
|
|
||||
|
This module comes under Odoo Email Marketing. |
||||
|
It will Use for Emailing. It could be use for Bulk |
||||
|
Mailing and Single Mailing . Email Template use for |
||||
|
constructing Email Content.It includes Mail reports |
||||
|
and Bounce Checking Option, here user can Konw the mail status. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
After the installation,in email marketting settings user can see sendgrid api setting field by ticking in check box a new text field will appear here user can set the API key by saving it key will be save in the system ,in email marketting configuration includes a sub menu sendgrid email template details here user can create email templates . in configuration have another menu called sendgrid from emails this menu is used for creating new from emails for using in malling. in mailing menu create a new mail here user can see a new page view called sendgrid emails here we can set the template and another specifications, using sendgrid button on top user can send the mail. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
|
||||
|
For saving the API key configuration have check box field sendgrid api by ticking in check box a new text field will appear here user can set the API key by saving it key will be save in the system. |
||||
|
|
||||
|
|
||||
|
Company |
||||
|
------- |
||||
|
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
||||
|
|
||||
|
Credits |
||||
|
------- |
||||
|
* Developer: |
||||
|
Noushid Khan.P |
||||
|
|
||||
|
Contacts |
||||
|
-------- |
||||
|
* Mail Contact : odoo@cybrosys.com |
||||
|
* Website : https://cybrosys.com |
||||
|
|
||||
|
Bug Tracker |
||||
|
----------- |
||||
|
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
||||
|
|
||||
|
Maintainer |
||||
|
========== |
||||
|
.. image:: https://cybrosys.com/images/logo.png |
||||
|
:target: https://cybrosys.com |
||||
|
|
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
||||
|
|
||||
|
Further information |
||||
|
=================== |
||||
|
HTML Description: `<static/description/index.html>`__ |
||||
|
|
||||
|
|
@ -0,0 +1,24 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). |
||||
|
# Author: Noushid Khan.P (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
from . import models |
@ -0,0 +1,53 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). |
||||
|
# Author: Noushid Khan.P (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
{ |
||||
|
'name': 'Mass Mailing With SendGrid', |
||||
|
'version': '13.0.1.0.0', |
||||
|
'summary': 'Mass Mailing using SendGrid API', |
||||
|
'description': 'Mass Mailing using SendGrid API', |
||||
|
'category': 'Marketing', |
||||
|
'author': 'Cybrosys Techno Solutions', |
||||
|
'maintainer': 'Cybrosys Techno Solutions', |
||||
|
'company': 'Cybrosys Techno Solutions', |
||||
|
'website': 'https://www.cybrosys.com', |
||||
|
'depends': [ |
||||
|
'crm', |
||||
|
'mass_mailing', |
||||
|
'base', |
||||
|
'hr_recruitment', |
||||
|
'event' |
||||
|
], |
||||
|
'data': [ |
||||
|
'security/ir.model.access.csv', |
||||
|
'views/view.xml', |
||||
|
'views/mail_view.xml', |
||||
|
'views/ir_config_view.xml', |
||||
|
'views/res_config_view.xml' |
||||
|
], |
||||
|
'license': 'AGPL-3', |
||||
|
'images': ['static/description/banner.png'], |
||||
|
'installable': True, |
||||
|
'application': False, |
||||
|
'auto_install': False, |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
## Module <sendgrid_email> |
||||
|
|
||||
|
#### 30.01.2020 |
||||
|
#### Version 13.0.1.0.0 |
||||
|
##### ADD |
||||
|
- Initial commit for sendgrid_email. |
||||
|
|
@ -0,0 +1,29 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). |
||||
|
# Author: Noushid Khan.P (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
from . import model |
||||
|
from . import email_send |
||||
|
from . import email_template |
||||
|
from . import mail_mail |
||||
|
from . import ir_config_parameter |
||||
|
from . import res_config_settings |
@ -0,0 +1,32 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). |
||||
|
# Author: Noushid Khan.P (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
from odoo import models, fields |
||||
|
|
||||
|
|
||||
|
class EmailDetails(models.Model): |
||||
|
_name = "email.sent" |
||||
|
_description = 'Email From Mails' |
||||
|
|
||||
|
name = fields.Char(string="Name", required=True) |
||||
|
email_id = fields.Char(string="Email ID", required=True) |
@ -0,0 +1,117 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). |
||||
|
# Author: Noushid Khan.P (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
import json |
||||
|
|
||||
|
from odoo import models, fields, _ |
||||
|
import http.client |
||||
|
|
||||
|
from odoo.exceptions import UserError |
||||
|
|
||||
|
|
||||
|
class EmailTemplateDetails(models.Model): |
||||
|
_name = "email.template" |
||||
|
_rec_name = "temp_name" |
||||
|
_description = "Template Creation" |
||||
|
|
||||
|
temp_name = fields.Char(string="Template Name", required=True) |
||||
|
generation = fields.Char(string="Template Generation", default="Dynamic", readonly=True) |
||||
|
ver_name = fields.Char(string="Version Name") |
||||
|
ver_subject = fields.Char(string="Version Subject", required=True) |
||||
|
ver_editor = fields.Selection([('design', "Design"), ('code', "Code")], string="Version Editor", default="design") |
||||
|
temp_cont = fields.Html(string="Template Content", help="content convert to html code", translate=True, sanitize=False) |
||||
|
temp_id = fields.Char(string="Template ID") |
||||
|
|
||||
|
def create_temp(self): |
||||
|
""" |
||||
|
function is used for creating Mail Template |
||||
|
|
||||
|
""" |
||||
|
api_key = "" |
||||
|
company_id = self.env.company |
||||
|
temp_name = self.temp_name |
||||
|
temp_gen = self.generation |
||||
|
api_info = self.env['ir.config_parameter'].search( |
||||
|
[('key', '=', "SendGrid API Key " + company_id.name + "")]) |
||||
|
if not api_info: |
||||
|
raise UserError(_("It Needs API Key")) |
||||
|
if api_info.company_id.id == self.env.company.id: |
||||
|
api_key = api_info.value |
||||
|
if not api_key and api_key == "": |
||||
|
raise UserError(_("Your Company Needs an API Key")) |
||||
|
conn = http.client.HTTPSConnection("api.sendgrid.com") |
||||
|
|
||||
|
payload = "{\"name\":\""+temp_name+"\",\"generation\":\"dynamic\"}" |
||||
|
|
||||
|
headers = { |
||||
|
'authorization': "Bearer "+api_key+"", |
||||
|
'content-type': "application/json" |
||||
|
} |
||||
|
|
||||
|
conn.request("POST", "/v3/templates", payload, headers) |
||||
|
|
||||
|
res = conn.getresponse() |
||||
|
data = res.read() |
||||
|
|
||||
|
temp_data = json.loads(data.decode("utf-8")) |
||||
|
self.temp_id = temp_data['id'] |
||||
|
|
||||
|
def create_ver(self): |
||||
|
""" |
||||
|
Function is used for creating mail content to the |
||||
|
Created Template. |
||||
|
|
||||
|
""" |
||||
|
api_key = "" |
||||
|
if self.temp_cont: |
||||
|
company_id = self.env.company |
||||
|
temp_cont = self.temp_cont |
||||
|
temp_id = self.temp_id |
||||
|
ver_name = self.ver_name |
||||
|
ver_sub = self.ver_subject |
||||
|
api_info = self.env['ir.config_parameter'].search( |
||||
|
[('key', '=', "SendGrid API Key " + company_id.name + "")]) |
||||
|
if not api_info: |
||||
|
raise UserError(_("It Needs API Key")) |
||||
|
if api_info.company_id.id == self.env.company.id: |
||||
|
api_key = api_info.value |
||||
|
if not api_key and api_key == "": |
||||
|
raise UserError(_("Your Company Needs an API Key")) |
||||
|
conn = http.client.HTTPSConnection("api.sendgrid.com") |
||||
|
upt_temp_cnt = (temp_cont.replace('"','')) |
||||
|
|
||||
|
payload = "{\"template_id\":\""+temp_id+"\",\"active\":1,\"name\":\""+ver_name+"\",\"html_content\":\""+upt_temp_cnt+"\",\"plain_content\":\"<%body%>\",\"subject\":\""+ver_sub+"\"}" |
||||
|
|
||||
|
headers = { |
||||
|
'authorization': "Bearer "+api_key+"", |
||||
|
'content-type': "application/json" |
||||
|
} |
||||
|
|
||||
|
conn.request("POST", "/v3/templates/"+temp_id+"/versions", payload, headers) |
||||
|
|
||||
|
# res = conn.getresponse() |
||||
|
# data = res.read() |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
@ -0,0 +1,43 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). |
||||
|
# Author: Noushid Khan.P (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
from odoo import models, fields, api |
||||
|
|
||||
|
|
||||
|
class SendGridAPI(models.Model): |
||||
|
_inherit = "ir.config_parameter" |
||||
|
|
||||
|
company_id = fields.Many2one('res.company', string="Company ID") |
||||
|
|
||||
|
@api.model |
||||
|
def create(self, vals_list): |
||||
|
""" |
||||
|
function is used for auto filling company |
||||
|
details to company_id |
||||
|
|
||||
|
""" |
||||
|
res = super(SendGridAPI, self).create(vals_list) |
||||
|
res.company_id = self.env.company.id |
||||
|
return res |
||||
|
|
||||
|
|
@ -0,0 +1,549 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). |
||||
|
# Author: Noushid Khan.P (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
import json |
||||
|
|
||||
|
from odoo import models, fields, api, _ |
||||
|
from odoo.exceptions import UserError |
||||
|
import http.client |
||||
|
|
||||
|
|
||||
|
class SendGridEmail(models.Model): |
||||
|
_inherit = 'mailing.mailing' |
||||
|
|
||||
|
email_temp = fields.Many2one("email.template", string="Email Template") |
||||
|
temp_id = fields.Char(string="Template ID") |
||||
|
from_email = fields.Many2one("email.sent", string="Sender Email") |
||||
|
to_email_partner = fields.Many2many("res.partner", string="Recipient Emails") |
||||
|
to_email_partner_check = fields.Boolean() |
||||
|
to_email_lead = fields.Many2many("crm.lead", string="Recipient Emails") |
||||
|
to_email_lead_check = fields.Boolean() |
||||
|
to_email_contact = fields.Many2many("mailing.contact", string="Recipient Emails") |
||||
|
to_email_contact_check = fields.Boolean() |
||||
|
to_email_applicant = fields.Many2many("hr.applicant", string="Recipient Emails") |
||||
|
to_email_applicant_check = fields.Boolean() |
||||
|
email_finder = fields.Integer(string="Email finder") |
||||
|
sent_count = fields.Integer(string="Send Count") |
||||
|
send_grid_check = fields.Boolean() |
||||
|
temp_check = fields.Boolean() |
||||
|
|
||||
|
def action_send_grid(self): |
||||
|
""" |
||||
|
function used for Sending emails using |
||||
|
SendGrid API using "sendgrid" Button |
||||
|
and creating report based on states. |
||||
|
|
||||
|
""" |
||||
|
company_id = self.env.company |
||||
|
api_key = "" |
||||
|
conn = http.client.HTTPSConnection("api.sendgrid.com") |
||||
|
if not self.temp_id: |
||||
|
raise UserError(_("It Needs A Template ID")) |
||||
|
if self.from_email: |
||||
|
from_email = self.from_email.email_id |
||||
|
from_name = self.from_email.name |
||||
|
else: |
||||
|
from_email = "noreply@johndoe.com" |
||||
|
from_name = "JohnDoe" |
||||
|
if self.to_email_partner: |
||||
|
api_info = self.env['ir.config_parameter'].search( |
||||
|
[('key', '=', "SendGrid API Key " + company_id.name + "")]) |
||||
|
if not api_info: |
||||
|
raise UserError(_("It Needs API Key")) |
||||
|
if api_info.company_id.id == self.env.company.id: |
||||
|
api_key = api_info.value |
||||
|
if not api_key and api_key == "": |
||||
|
raise UserError(_("Your Company Needs an API Key")) |
||||
|
for data in self.to_email_partner: |
||||
|
to_email = data.email |
||||
|
to_name = data.name |
||||
|
to_company = data.company_name |
||||
|
if not to_company: |
||||
|
to_company = "" |
||||
|
temp_id = self.temp_id |
||||
|
if to_email: |
||||
|
payload = "{\"personalizations\":[{\"to\":[{\"email\":\"" + to_email + "\"}],\"dynamic_template_data\":{\"firstname\":\"" + to_name + "\",\"english\":\"true\",\"company\":\"" + to_company + "\"},\"subject\":\"Official Mail\"}],\"from\":{\"email\":\"" + from_email + "\",\"name\":\"" + from_name + "\"},\"template_id\":\"" + temp_id + "\"}" |
||||
|
|
||||
|
headers = { |
||||
|
'authorization': "Bearer " + api_key + "", |
||||
|
'content-type': "application/json" |
||||
|
} |
||||
|
|
||||
|
conn.request("POST", "/v3/mail/send", payload, headers) |
||||
|
|
||||
|
res = conn.getresponse() |
||||
|
data_msg = res.read() |
||||
|
error_msg = '' |
||||
|
if data_msg.decode("utf-8"): |
||||
|
error_data = json.loads(data_msg.decode("utf-8")) |
||||
|
error_msg = error_data['errors'][0]['message'] |
||||
|
if not data_msg.decode("utf-8"): |
||||
|
self.sent_count += 1 |
||||
|
self.write({ |
||||
|
'state': 'done' |
||||
|
}) |
||||
|
self.env['email.api'].create({ |
||||
|
'name': self.subject, |
||||
|
'to_email_partner': data.id, |
||||
|
'to_email': to_email, |
||||
|
'recipient_name': to_name, |
||||
|
'company_name': to_company, |
||||
|
'from_email': self.from_email.id, |
||||
|
'temp_type': self.email_temp.id, |
||||
|
'temp_id': self.temp_id, |
||||
|
'to_email_partner_check': True, |
||||
|
'email_finder': self.id |
||||
|
}) |
||||
|
|
||||
|
elif error_msg: |
||||
|
self.env['email.api'].create({ |
||||
|
'name': self.subject, |
||||
|
'to_email_partner': data.id, |
||||
|
'to_email': to_email, |
||||
|
'recipient_name': to_name, |
||||
|
'company_name': to_company, |
||||
|
'from_email': self.from_email.id, |
||||
|
'temp_type': self.email_temp.id, |
||||
|
'temp_id': self.temp_id, |
||||
|
'error_msg': error_msg, |
||||
|
'state': 'error', |
||||
|
'to_email_partner_check': True, |
||||
|
'error_check': True, |
||||
|
'email_finder': self.id |
||||
|
}) |
||||
|
self.email_finder = self.id |
||||
|
self.send_grid_check = True |
||||
|
elif self.to_email_lead: |
||||
|
api_info = self.env['ir.config_parameter'].search( |
||||
|
[('key', '=', "SendGrid API Key " + company_id.name + "")]) |
||||
|
if not api_info: |
||||
|
raise UserError(_("It Needs API Key")) |
||||
|
if api_info.company_id.id == self.env.company.id: |
||||
|
api_key = api_info.value |
||||
|
if not api_key and api_key == "": |
||||
|
raise UserError(_("Your Company Needs an API Key")) |
||||
|
for data in self.to_email_lead: |
||||
|
to_email = data.email_from |
||||
|
to_name = data.contact_name |
||||
|
if not to_name: |
||||
|
raise UserError(_("Your Lead Needs A Contact Name")) |
||||
|
to_company = data.partner_name |
||||
|
if not to_company: |
||||
|
to_company = "" |
||||
|
temp_id = self.temp_id |
||||
|
payload = "" |
||||
|
if to_email: |
||||
|
payload = "{\"personalizations\":[{\"to\":[{\"email\":\"" + to_email + "\"}],\"dynamic_template_data\":{\"firstname\":\"" + to_name + "\",\"english\":\"true\",\"company\":\"" + to_company + "\"},\"subject\":\"Official Mail\"}],\"from\":{\"email\":\"" + from_email + "\",\"name\":\"" + from_name + "\"},\"template_id\":\"" + temp_id + "\"}" |
||||
|
|
||||
|
headers = { |
||||
|
'authorization': "Bearer " + api_key + "", |
||||
|
'content-type': "application/json" |
||||
|
} |
||||
|
|
||||
|
conn.request("POST", "/v3/mail/send", payload, headers) |
||||
|
|
||||
|
res = conn.getresponse() |
||||
|
data_msg = res.read() |
||||
|
|
||||
|
error_msg = '' |
||||
|
if data_msg.decode("utf-8"): |
||||
|
error_data = json.loads(data_msg.decode("utf-8")) |
||||
|
error_msg = error_data['errors'][0]['message'] |
||||
|
if not data_msg.decode("utf-8"): |
||||
|
self.sent_count += 1 |
||||
|
self.write({ |
||||
|
'state': 'done' |
||||
|
}) |
||||
|
self.env['email.api'].create({ |
||||
|
'name': self.subject, |
||||
|
'to_email_lead': data.id, |
||||
|
'to_email': to_email, |
||||
|
'recipient_name': to_name, |
||||
|
'company_name': to_company, |
||||
|
'from_email': self.from_email.id, |
||||
|
'temp_type': self.email_temp.id, |
||||
|
'temp_id': self.temp_id, |
||||
|
'to_email_lead_check': True, |
||||
|
'email_finder': self.id |
||||
|
}) |
||||
|
|
||||
|
elif error_msg: |
||||
|
self.env['email.api'].create({ |
||||
|
'name': self.subject, |
||||
|
'to_email_lead': data.id, |
||||
|
'to_email': to_email, |
||||
|
'recipient_name': to_name, |
||||
|
'company_name': to_company, |
||||
|
'from_email': self.from_email.id, |
||||
|
'temp_type': self.email_temp.id, |
||||
|
'temp_id': self.temp_id, |
||||
|
'error_msg': error_msg, |
||||
|
'state': 'error', |
||||
|
'to_email_lead_check': True, |
||||
|
'error_check': True, |
||||
|
'email_finder': self.id |
||||
|
}) |
||||
|
self.email_finder = self.id |
||||
|
self.send_grid_check = True |
||||
|
elif self.to_email_contact: |
||||
|
api_info = self.env['ir.config_parameter'].search( |
||||
|
[('key', '=', "SendGrid API Key " + company_id.name + "")]) |
||||
|
if not api_info: |
||||
|
raise UserError(_("It Needs API Key")) |
||||
|
if api_info.company_id.id == self.env.company.id: |
||||
|
api_key = api_info.value |
||||
|
if not api_key and api_key == "": |
||||
|
raise UserError(_("Your Company Needs an API Key")) |
||||
|
for data in self.to_email_contact: |
||||
|
to_email = data.email |
||||
|
to_name = data.name |
||||
|
to_company = data.company_name |
||||
|
if not to_company: |
||||
|
to_company = "" |
||||
|
temp_id = self.temp_id |
||||
|
payload = "" |
||||
|
if to_email: |
||||
|
payload = "{\"personalizations\":[{\"to\":[{\"email\":\"" + to_email + "\"}],\"dynamic_template_data\":{\"firstname\":\"" + to_name + "\",\"english\":\"true\",\"company\":\"" + to_company + "\"},\"subject\":\"Official Mail\"}],\"from\":{\"email\":\"" + from_email + "\",\"name\":\"" + from_name + "\"},\"template_id\":\"" + temp_id + "\"}" |
||||
|
|
||||
|
headers = { |
||||
|
'authorization': "Bearer " + api_key + "", |
||||
|
'content-type': "application/json" |
||||
|
} |
||||
|
|
||||
|
conn.request("POST", "/v3/mail/send", payload, headers) |
||||
|
|
||||
|
res = conn.getresponse() |
||||
|
data_msg = res.read() |
||||
|
|
||||
|
error_msg = '' |
||||
|
if data_msg.decode("utf-8"): |
||||
|
error_data = json.loads(data_msg.decode("utf-8")) |
||||
|
error_msg = error_data['errors'][0]['message'] |
||||
|
if not data_msg.decode("utf-8"): |
||||
|
self.sent_count += 1 |
||||
|
self.write({ |
||||
|
'state': 'done' |
||||
|
}) |
||||
|
self.env['email.api'].create({ |
||||
|
'name': self.subject, |
||||
|
'to_email_contact': data.id, |
||||
|
'to_email': to_email, |
||||
|
'recipient_name': to_name, |
||||
|
'company_name': to_company, |
||||
|
'from_email': self.from_email.id, |
||||
|
'temp_type': self.email_temp.id, |
||||
|
'temp_id': self.temp_id, |
||||
|
'to_email_contact_check': True, |
||||
|
'email_finder': self.id |
||||
|
}) |
||||
|
|
||||
|
elif error_msg: |
||||
|
self.env['email.api'].create({ |
||||
|
'name': self.subject, |
||||
|
'to_email_contact': data.id, |
||||
|
'to_email': to_email, |
||||
|
'recipient_name': to_name, |
||||
|
'company_name': to_company, |
||||
|
'from_email': self.from_email.id, |
||||
|
'temp_type': self.email_temp.id, |
||||
|
'temp_id': self.temp_id, |
||||
|
'error_msg': error_msg, |
||||
|
'state': 'error', |
||||
|
'to_email_contact_check': True, |
||||
|
'error_check': True, |
||||
|
'email_finder': self.id |
||||
|
}) |
||||
|
self.email_finder = self.id |
||||
|
self.send_grid_check = True |
||||
|
elif self.to_email_applicant: |
||||
|
api_info = self.env['ir.config_parameter'].search( |
||||
|
[('key', '=', "SendGrid API Key " + company_id.name + "")]) |
||||
|
if not api_info: |
||||
|
raise UserError(_("It Needs API Key")) |
||||
|
if api_info.company_id.id == self.env.company.id: |
||||
|
api_key = api_info.value |
||||
|
if not api_key and api_key == "": |
||||
|
raise UserError(_("Your Company Needs an API Key")) |
||||
|
for data in self.to_email_applicant: |
||||
|
to_email = data.email_from |
||||
|
to_name = data.partner_name |
||||
|
to_company = data.company_id.name |
||||
|
if not to_company: |
||||
|
to_company = "" |
||||
|
temp_id = self.temp_id |
||||
|
payload = "" |
||||
|
if to_email: |
||||
|
payload = "{\"personalizations\":[{\"to\":[{\"email\":\"" + to_email + "\"}],\"dynamic_template_data\":{\"firstname\":\"" + to_name + "\",\"english\":\"true\",\"company\":\"" + to_company + "\"},\"subject\":\"Official Mail\"}],\"from\":{\"email\":\"" + from_email + "\",\"name\":\"" + from_name + "\"},\"template_id\":\"" + temp_id + "\"}" |
||||
|
|
||||
|
headers = { |
||||
|
'authorization': "Bearer " + api_key + "", |
||||
|
'content-type': "application/json" |
||||
|
} |
||||
|
|
||||
|
conn.request("POST", "/v3/mail/send", payload, headers) |
||||
|
|
||||
|
res = conn.getresponse() |
||||
|
data_msg = res.read() |
||||
|
|
||||
|
error_msg = '' |
||||
|
if data_msg.decode("utf-8"): |
||||
|
error_data = json.loads(data_msg.decode("utf-8")) |
||||
|
error_msg = error_data['errors'][0]['message'] |
||||
|
if not data_msg.decode("utf-8"): |
||||
|
self.sent_count += 1 |
||||
|
self.write({ |
||||
|
'state': 'done' |
||||
|
}) |
||||
|
self.env['email.api'].create({ |
||||
|
'name': self.subject, |
||||
|
'to_email_applicant': data.id, |
||||
|
'to_email': to_email, |
||||
|
'recipient_name': to_name, |
||||
|
'company_name': to_company, |
||||
|
'from_email': self.from_email.id, |
||||
|
'temp_type': self.email_temp.id, |
||||
|
'temp_id': self.temp_id, |
||||
|
'to_email_applicant_check': True, |
||||
|
'email_finder': self.id |
||||
|
}) |
||||
|
|
||||
|
elif error_msg: |
||||
|
self.env['email.api'].create({ |
||||
|
'name': self.subject, |
||||
|
'to_email_applicant': data.id, |
||||
|
'to_email': to_email, |
||||
|
'recipient_name': to_name, |
||||
|
'company_name': to_company, |
||||
|
'from_email': self.from_email.id, |
||||
|
'temp_type': self.email_temp.id, |
||||
|
'temp_id': self.temp_id, |
||||
|
'error_msg': error_msg, |
||||
|
'state': 'error', |
||||
|
'email_finder': self.id, |
||||
|
'to_email_applicant_check': True, |
||||
|
'error_check': True |
||||
|
}) |
||||
|
self.email_finder = self.id |
||||
|
self.send_grid_check = True |
||||
|
|
||||
|
@api.onchange('email_temp', 'mailing_model_id', 'contact_list_ids') |
||||
|
def temp_details(self): |
||||
|
""" |
||||
|
function used for filling subject and recipients emails |
||||
|
based on template and recipient emails |
||||
|
|
||||
|
""" |
||||
|
if self.email_temp: |
||||
|
self.temp_check = True |
||||
|
self.subject = self.email_temp.ver_subject |
||||
|
self.temp_id = self.email_temp.temp_id |
||||
|
self.body_html = self.email_temp.temp_cont |
||||
|
self.body_arch = self.email_temp.temp_cont |
||||
|
else: |
||||
|
self.temp_check = False |
||||
|
|
||||
|
if self.mailing_model_real == "sale.order" or self.mailing_model_real == "event.registration" or self.mailing_model_real == "event.track": |
||||
|
self.to_email_contact = False |
||||
|
self.to_email_lead = False |
||||
|
self.to_email_applicant = False |
||||
|
self.mailing_domain = "[]" |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_partner = email_ids.partner_id |
||||
|
elif self.mailing_model_real == "crm.lead": |
||||
|
self.to_email_contact = False |
||||
|
self.to_email_partner = False |
||||
|
self.to_email_applicant = False |
||||
|
self.mailing_domain = "[]" |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_lead = email_ids |
||||
|
elif self.mailing_model_real == "mailing.contact": |
||||
|
self.to_email_partner = False |
||||
|
self.to_email_lead = False |
||||
|
self.to_email_applicant = False |
||||
|
self.mailing_domain = "[]" |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_contact = email_ids |
||||
|
if self.contact_list_ids: |
||||
|
email_ids = self.env[self.mailing_model_real].search( |
||||
|
[('id', '=', mai_data), ('list_ids', '=', self.contact_list_ids.ids)]) |
||||
|
self.to_email_contact = email_ids |
||||
|
|
||||
|
elif self.mailing_model_real == "hr.applicant": |
||||
|
self.to_email_contact = False |
||||
|
self.to_email_lead = False |
||||
|
self.to_email_partner = False |
||||
|
self.mailing_domain = "[]" |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_applicant = email_ids |
||||
|
|
||||
|
else: |
||||
|
self.to_email_contact = False |
||||
|
self.to_email_lead = False |
||||
|
self.to_email_applicant = False |
||||
|
self.mailing_domain = "[]" |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_partner = email_ids |
||||
|
|
||||
|
@api.onchange('mailing_domain') |
||||
|
def get_mails_recipients(self): |
||||
|
""" |
||||
|
function used for filtering based on domain |
||||
|
filter |
||||
|
|
||||
|
""" |
||||
|
if self.mailing_model_real == "sale.order" or self.mailing_model_real == "event.registration" or self.mailing_model_real == "event.track": |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_partner = email_ids.partner_id |
||||
|
elif self.mailing_model_real == "crm.lead": |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_lead = email_ids |
||||
|
elif self.mailing_model_real == "mailing.contact": |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_contact = email_ids |
||||
|
elif self.mailing_model_real == "hr.applicant": |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_applicant = email_ids |
||||
|
else: |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
email_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
if email_ids: |
||||
|
self.to_email_partner = email_ids |
||||
|
|
||||
|
@api.onchange('to_email_partner', 'to_email_lead', 'to_email_contact', 'to_email_applicant') |
||||
|
def show_hide_fields(self): |
||||
|
""" |
||||
|
function is used for Enabling Needed |
||||
|
recipient mail fields by changing check box |
||||
|
values. |
||||
|
|
||||
|
""" |
||||
|
if self.to_email_partner: |
||||
|
self.to_email_partner_check = True |
||||
|
else: |
||||
|
self.to_email_partner_check = False |
||||
|
if self.to_email_lead: |
||||
|
self.to_email_lead_check = True |
||||
|
else: |
||||
|
self.to_email_lead_check = False |
||||
|
if self.to_email_contact: |
||||
|
self.to_email_contact_check = True |
||||
|
else: |
||||
|
self.to_email_contact_check = False |
||||
|
if self.to_email_applicant: |
||||
|
self.to_email_applicant_check = True |
||||
|
else: |
||||
|
self.to_email_applicant_check = False |
||||
|
|
||||
|
def _action_view_documents_filtered(self, view_filter): |
||||
|
""" |
||||
|
function is used for returning send view in |
||||
|
needed recipient tree view |
||||
|
|
||||
|
""" |
||||
|
if view_filter == 'sent' and self.temp_id: |
||||
|
res_ids = [] |
||||
|
for mass_mailing in self: |
||||
|
mai_data = mass_mailing.sudo()._get_recipients() |
||||
|
res_ids = self.env[self.mailing_model_real].search([('id', '=', mai_data)]) |
||||
|
model_name = self.env['ir.model']._get(self.mailing_model_real).display_name |
||||
|
return { |
||||
|
'name': model_name, |
||||
|
'type': 'ir.actions.act_window', |
||||
|
'view_mode': 'tree', |
||||
|
'res_model': self.mailing_model_real, |
||||
|
'domain': [('id', 'in', res_ids.ids)], |
||||
|
'context': dict(self._context, create=False) |
||||
|
} |
||||
|
else: |
||||
|
return super(SendGridEmail, self)._action_view_documents_filtered(view_filter) |
||||
|
|
||||
|
def _compute_statistics(self): |
||||
|
""" |
||||
|
function is used for computing Send mails Smart button |
||||
|
count |
||||
|
|
||||
|
""" |
||||
|
self.env.cr.execute(""" |
||||
|
SELECT |
||||
|
m.id as mailing_id, |
||||
|
COUNT(s.id) AS expected, |
||||
|
COUNT(CASE WHEN s.sent is not null THEN 1 ELSE null END) AS sent, |
||||
|
COUNT(CASE WHEN s.scheduled is not null AND s.sent is null AND s.exception is null AND s.ignored is null AND s.bounced is null THEN 1 ELSE null END) AS scheduled, |
||||
|
COUNT(CASE WHEN s.scheduled is not null AND s.sent is null AND s.exception is null AND s.ignored is not null THEN 1 ELSE null END) AS ignored, |
||||
|
COUNT(CASE WHEN s.sent is not null AND s.exception is null AND s.bounced is null THEN 1 ELSE null END) AS delivered, |
||||
|
COUNT(CASE WHEN s.opened is not null THEN 1 ELSE null END) AS opened, |
||||
|
COUNT(CASE WHEN s.clicked is not null THEN 1 ELSE null END) AS clicked, |
||||
|
COUNT(CASE WHEN s.replied is not null THEN 1 ELSE null END) AS replied, |
||||
|
COUNT(CASE WHEN s.bounced is not null THEN 1 ELSE null END) AS bounced, |
||||
|
COUNT(CASE WHEN s.exception is not null THEN 1 ELSE null END) AS failed |
||||
|
FROM |
||||
|
mailing_trace s |
||||
|
RIGHT JOIN |
||||
|
mailing_mailing m |
||||
|
ON (m.id = s.mass_mailing_id) |
||||
|
WHERE |
||||
|
m.id IN %s |
||||
|
GROUP BY |
||||
|
m.id |
||||
|
""", (tuple(self.ids),)) |
||||
|
for row in self.env.cr.dictfetchall(): |
||||
|
total = row['expected'] = (row['expected'] - row['ignored']) or 1 |
||||
|
row['received_ratio'] = 100.0 * row['delivered'] / total |
||||
|
row['opened_ratio'] = 100.0 * row['opened'] / total |
||||
|
row['clicks_ratio'] = 100.0 * row['clicked'] / total |
||||
|
row['replied_ratio'] = 100.0 * row['replied'] / total |
||||
|
row['bounced_ratio'] = 100.0 * row['bounced'] / total |
||||
|
self.browse(row.pop('mailing_id')).update(row) |
||||
|
for mail in self: |
||||
|
if mail.temp_id: |
||||
|
mail.sent = mail.sent_count |
||||
|
else: |
||||
|
return super(SendGridEmail, self)._compute_statistics() |
@ -0,0 +1,137 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). |
||||
|
# Author: Noushid Khan.P (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
import json |
||||
|
|
||||
|
from odoo import models, fields, _ |
||||
|
import http.client |
||||
|
|
||||
|
from odoo.exceptions import UserError |
||||
|
|
||||
|
|
||||
|
class SendGridSendEmails(models.Model): |
||||
|
_name = "email.api" |
||||
|
_description = "Email Reports" |
||||
|
|
||||
|
name = fields.Char(string="Name") |
||||
|
company_name = fields.Char(string="Company Name") |
||||
|
recipient_name = fields.Char(string="Recipient Name") |
||||
|
to_email = fields.Char(string="Recipient Email ID") |
||||
|
to_email_partner = fields.Many2one("res.partner", string="Recipient Emails") |
||||
|
to_email_partner_check = fields.Boolean() |
||||
|
to_email_lead = fields.Many2one("crm.lead", string="Recipient Emails") |
||||
|
to_email_lead_check = fields.Boolean() |
||||
|
to_email_contact = fields.Many2one("mailing.contact", string="Recipient Emails") |
||||
|
to_email_contact_check = fields.Boolean() |
||||
|
to_email_applicant = fields.Many2one("hr.applicant", string="Recipient Emails") |
||||
|
to_email_applicant_check = fields.Boolean() |
||||
|
from_email = fields.Many2one("email.sent", string="Sender Email") |
||||
|
temp_type = fields.Many2one('email.template', string="Email Template") |
||||
|
temp_id = fields.Char(string="Template_id") |
||||
|
send_date = fields.Datetime(string="Send Date", readonly=True, default=fields.Datetime.now) |
||||
|
error_msg = fields.Text(string="Error Content", readonly=True) |
||||
|
error_check = fields.Boolean() |
||||
|
state = fields.Selection([('send', "Send"), ('error', "Error")], readonly=True, string="State", default='send') |
||||
|
bounce_msg = fields.Text(string="Bounce Message") |
||||
|
email_finder = fields.Integer(string="Email finder") |
||||
|
|
||||
|
def bounce_check(self): |
||||
|
""" |
||||
|
function is used for Checking Email Bounce |
||||
|
Status. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
conn = http.client.HTTPSConnection("api.sendgrid.com") |
||||
|
|
||||
|
payload = "{}" |
||||
|
|
||||
|
headers = {'authorization': "Bearer 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"} |
||||
|
|
||||
|
conn.request("GET", "/v3/suppression/bounces/" + self.to_email + "", payload, headers) |
||||
|
|
||||
|
res = conn.getresponse() |
||||
|
data = res.read() |
||||
|
|
||||
|
bounce_msg = json.loads(data.decode("utf-8")) |
||||
|
if bounce_msg: |
||||
|
self.bounce_msg = bounce_msg[0]['reason'] |
||||
|
|
||||
|
else: |
||||
|
self.bounce_msg = "This Email Is Not Bounced" |
||||
|
|
||||
|
def send_error_mails(self): |
||||
|
""" |
||||
|
function is used for Resending Error State |
||||
|
mails. |
||||
|
|
||||
|
""" |
||||
|
company_id = self.env.company |
||||
|
api_key = "" |
||||
|
for line in self: |
||||
|
if line.state == 'error': |
||||
|
if not line.temp_id: |
||||
|
raise UserError(_("It Needs A Template ID")) |
||||
|
if line.from_email: |
||||
|
from_email = line.from_email.email_id |
||||
|
else: |
||||
|
from_email = "noreply@johndoe.com" |
||||
|
api_info = self.env['ir.config_parameter'].search( |
||||
|
[('key', '=', "SendGrid API Key " + company_id.name + "")]) |
||||
|
if not api_info: |
||||
|
raise UserError(_("It Needs API Key")) |
||||
|
if api_info.company_id.id == self.env.company.id: |
||||
|
api_key = api_info.value |
||||
|
if not api_key and api_key == "": |
||||
|
raise UserError(_("Your Company Needs an API Key")) |
||||
|
conn = http.client.HTTPSConnection("api.sendgrid.com") |
||||
|
to_company = line.company_name |
||||
|
if not to_company: |
||||
|
to_company = "" |
||||
|
temp_id = line.temp_id |
||||
|
payload = "" |
||||
|
if line.to_email and line.recipient_name: |
||||
|
payload = "{\"personalizations\":[{\"to\":[{\"email\":\"" + line.to_email + "\"}],\"dynamic_template_data\":{\"firstname\":\"" + line.recipient_name + "\",\"english\":\"true\",\"company\":\"" + to_company + "\"},\"subject\":\"Official Mail\"}],\"from\":{\"email\":\"" + from_email + "\",},\"template_id\":\"" + temp_id + "\"}" |
||||
|
headers = { |
||||
|
'authorization': "Bearer " + api_key + "", |
||||
|
'content-type': "application/json" |
||||
|
} |
||||
|
|
||||
|
conn.request("POST", "/v3/mail/send", payload, headers) |
||||
|
|
||||
|
res = conn.getresponse() |
||||
|
data_msg = res.read() |
||||
|
|
||||
|
if data_msg.decode("utf-8"): |
||||
|
error_data = json.loads(data_msg.decode("utf-8")) |
||||
|
line.error_msg = error_data['errors'][0]['message'] |
||||
|
if not data_msg.decode("utf-8"): |
||||
|
line.state = 'send' |
||||
|
line.error_msg = "" |
||||
|
line.error_check = False |
||||
|
email_id_use = self.env['mailing.mailing'].search([('id', '=', line.email_finder)]) |
||||
|
email_id_use.send_grid_check = True |
||||
|
email_id_use.sent_count += 1 |
||||
|
email_id_use.write({ |
||||
|
'state': 'done' |
||||
|
}) |
@ -0,0 +1,39 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
################################################################################### |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2019-TODAY Cybrosys Technologies (<https://www.cybrosys.com>). |
||||
|
# Author: Noushid Khan.P (<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# This program is free software: you can modify |
||||
|
# it under the terms of the GNU Affero General Public License (AGPL) as |
||||
|
# published by the Free Software Foundation, either version 3 of the |
||||
|
# License, or (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
################################################################################### |
||||
|
|
||||
|
from odoo import models, fields, api, _ |
||||
|
|
||||
|
|
||||
|
class SendGridApiConfig(models.TransientModel): |
||||
|
_inherit = 'res.config.settings' |
||||
|
|
||||
|
send_grid_api_check = fields.Boolean(string="SendGrid API") |
||||
|
send_grid_api_value = fields.Char(string='API key') |
||||
|
|
||||
|
def set_values(self): |
||||
|
""" save values in the settings fields """ |
||||
|
|
||||
|
super(SendGridApiConfig, self).set_values() |
||||
|
company_id = self.env.company |
||||
|
self.env['ir.config_parameter'].sudo().set_param("SendGrid API Key "+company_id.name+"", |
||||
|
self.send_grid_api_value) |
|
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 123 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 122 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 54 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 47 KiB |
@ -0,0 +1,18 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<data> |
||||
|
|
||||
|
<record id="ir_config_inherit_view" model="ir.ui.view"> |
||||
|
<field name="name">company config</field> |
||||
|
<field name="model">ir.config_parameter</field> |
||||
|
<field name="inherit_id" ref="base.view_ir_config_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//field[@name='value']" |
||||
|
position="after"> |
||||
|
<field name="company_id" invisible="1"/> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,99 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<data> |
||||
|
|
||||
|
<record id="send_mass_mailing_view" model="ir.ui.view"> |
||||
|
<field name="name">SendGrid Mass MAil</field> |
||||
|
<field name="model">mailing.mailing</field> |
||||
|
<field name="inherit_id" ref="mass_mailing.view_mail_mass_mailing_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="/form/header" position="inside"> |
||||
|
<button name="action_send_grid" type="object" |
||||
|
attrs="{'invisible': [('state', 'in', ('in_queue', 'done'))]}" class="oe_highlight" |
||||
|
string="SendGrid" |
||||
|
confirm="This will send the email to all recipients. Do you still want to proceed ?"/> |
||||
|
</xpath> |
||||
|
<xpath expr="/form/sheet/notebook/page[@name='mail_body']" |
||||
|
position="after"> |
||||
|
<page string="SendGrid Email" name="send_grid"> |
||||
|
<group> |
||||
|
<field name="email_temp"/> |
||||
|
<field name="temp_id"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="to_email_partner_check" invisible="1"/> |
||||
|
<field name="to_email_lead_check" invisible="1"/> |
||||
|
<field name="to_email_contact_check" invisible="1"/> |
||||
|
<field name="to_email_applicant_check" invisible="1"/> |
||||
|
<field name="to_email_partner" widget="many2many_tags" |
||||
|
attrs="{'invisible': [('to_email_partner_check', '=', False)]}"/> |
||||
|
<field name="to_email_lead" widget="many2many_tags" |
||||
|
attrs="{'invisible': [('to_email_lead_check', '=',False)]}"/> |
||||
|
<field name="to_email_contact" widget="many2many_tags" |
||||
|
attrs="{'invisible': [('to_email_contact_check', '=',False)]}"/> |
||||
|
<field name="to_email_applicant" widget="many2many_tags" |
||||
|
attrs="{'invisible': [('to_email_applicant_check', '=',False)]}"/> |
||||
|
<field name="from_email"/> |
||||
|
<field name="email_finder" invisible="1"/> |
||||
|
<field name="sent_count" invisible="1"/> |
||||
|
<field name="send_grid_check" invisible="1"/> |
||||
|
<field name="temp_check" invisible="1"/> |
||||
|
</group> |
||||
|
</page> |
||||
|
</xpath> |
||||
|
<xpath expr="//button[@name='action_view_delivered']" position="replace"> |
||||
|
<button name="action_view_delivered" type="object" |
||||
|
context="{'search_default_filter_delivered': True}" |
||||
|
attrs="{'invisible': ['|',('state', 'in', ('draft','test')),('send_grid_check','=',True)]}" |
||||
|
class="oe_stat_button"> |
||||
|
<field name="received_ratio" string="Received" widget="percentpie"/> |
||||
|
</button> |
||||
|
</xpath> |
||||
|
<xpath expr="//button[@name='action_redirect_to_leads']" position="replace"> |
||||
|
<button name="action_redirect_to_leads" type="object" icon="fa-star" class="oe_stat_button" |
||||
|
groups="sales_team.group_sale_salesman" |
||||
|
attrs="{'invisible': ['|','|',('state', '=', 'draft'), ('crm_lead_activated', '=', False), ('send_grid_check','=',True)]}"> |
||||
|
<field name="crm_lead_count" string="Leads" widget="statinfo"/> |
||||
|
</button> |
||||
|
</xpath> |
||||
|
<xpath expr="//button[@name='action_redirect_to_opportunities']" position="replace"> |
||||
|
<button name="action_redirect_to_opportunities" type="object" icon="fa-star" class="oe_stat_button" |
||||
|
groups="sales_team.group_sale_salesman" |
||||
|
attrs="{'invisible': ['|','|',('state', '=', 'draft'), ('crm_lead_activated', '=', True), ('send_grid_check','=',True)]}"> |
||||
|
<field name="crm_opportunities_count" string="Opportunities" widget="statinfo"/> |
||||
|
</button> |
||||
|
</xpath> |
||||
|
<xpath expr="//button[@name='action_view_opened']" position="replace"> |
||||
|
<button name="action_view_opened" type="object" context="{'search_default_filter_opened': True}" |
||||
|
attrs="{'invisible': ['|',('state', 'in', ('draft','test')),('send_grid_check','=',True)]}" |
||||
|
class="oe_stat_button"> |
||||
|
<field name="opened_ratio" string="Opened" widget="percentpie"/> |
||||
|
</button> |
||||
|
</xpath> |
||||
|
<xpath expr="//button[@name='action_view_replied']" position="replace"> |
||||
|
<button name="action_view_replied" type="object" context="{'search_default_filter_replied': True}" |
||||
|
attrs="{'invisible': ['|',('state', 'in', ('draft','test')),('send_grid_check','=',True)]}" |
||||
|
class="oe_stat_button"> |
||||
|
<field name="replied_ratio" string="Replied" widget="percentpie"/> |
||||
|
</button> |
||||
|
</xpath> |
||||
|
<xpath expr="//button[@name='action_view_bounced']" position="replace"> |
||||
|
<button name="action_view_bounced" type="object" context="{'search_default_filter_bounced': True}" |
||||
|
attrs="{'invisible': ['|',('state', 'in', ('draft','test')),('send_grid_check','=',True)]}" |
||||
|
class="oe_stat_button"> |
||||
|
<field name="bounced_ratio" string="Bounced" widget="percentpie"/> |
||||
|
</button> |
||||
|
</xpath> |
||||
|
<xpath expr="//field[@name='body_arch']" position="replace"> |
||||
|
<field name="body_arch" class="o_mail_body oe_edit_only" widget="mass_mailing_html" |
||||
|
options="{ |
||||
|
'snippets': 'mass_mailing.email_designer_snippets', |
||||
|
'cssEdit': 'mass_mailing.iframe_css_assets_edit', |
||||
|
'inline-field': 'body_html' |
||||
|
}" attrs="{'readonly': ['|',('state', 'in', ('sending', 'done')),('temp_check','=', True)]}"/> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,37 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<data> |
||||
|
<record id="res_config_settings_send_grid_view_form" model="ir.ui.view"> |
||||
|
<field name="name">res.config.settings.view.form.inherit.send.grid</field> |
||||
|
<field name="model">res.config.settings</field> |
||||
|
<field name="priority" eval="70"/> |
||||
|
<field name="inherit_id" ref="base.res_config_settings_view_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//div[hasclass('settings')]" |
||||
|
position="inside"> |
||||
|
<div class="app_settings_block"> |
||||
|
<div class="row mt16 o_settings_container"> |
||||
|
<div class="col-lg-6 o_setting_box col-12"> |
||||
|
<div class="o_setting_left_pane"> |
||||
|
<field name="send_grid_api_check"/> |
||||
|
</div> |
||||
|
<div class="o_setting_right_pane"> |
||||
|
<label for="send_grid_api_check"/> |
||||
|
<div class="text-muted"> |
||||
|
Use API key For SendGrid Service |
||||
|
</div> |
||||
|
<div class="content-group" |
||||
|
attrs="{'invisible': [('send_grid_api_check', '=', False)]}"> |
||||
|
<div class="mt16"> |
||||
|
<field name="send_grid_api_value"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</data> |
||||
|
</odoo> |
@ -0,0 +1,218 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<data> |
||||
|
|
||||
|
<record id="email_sending_action" model="ir.actions.act_window"> |
||||
|
<field name="name">Send Emails</field> |
||||
|
<field name="res_model">email.api</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="context">{'group_by': 'name'}</field> |
||||
|
<field name="help" type="html"> |
||||
|
<p class="oe_view_nocontent_create">Create contacts |
||||
|
</p> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="send_emails_tree_view" model="ir.ui.view"> |
||||
|
<field name="name">Send Emails tree</field> |
||||
|
<field name="model">email.api</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Send Emails" delete="0" create="0"> |
||||
|
<field name="name"/> |
||||
|
<field name="to_email"/> |
||||
|
<field name="send_date"/> |
||||
|
<field name="state"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="send_emails_free_view" model="ir.ui.view"> |
||||
|
<field name="name">Send Emails Form</field> |
||||
|
<field name="model">email.api</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Email Details" delete="0" create="0" edit="0"> |
||||
|
<header> |
||||
|
<field name="state" widget="statusbar"/> |
||||
|
</header> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<field name="name"/> |
||||
|
<field name="send_date"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="temp_type"/> |
||||
|
<field name="temp_id"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="to_email_partner_check" invisible="1"/> |
||||
|
<field name="to_email_lead_check" invisible="1"/> |
||||
|
<field name="to_email_contact_check" invisible="1"/> |
||||
|
<field name="to_email_applicant_check" invisible="1"/> |
||||
|
<field name="to_email_partner" |
||||
|
attrs="{'invisible': [('to_email_partner_check', '=', False)]}"/> |
||||
|
<field name="to_email_lead" attrs="{'invisible': [('to_email_lead_check', '=',False)]}"/> |
||||
|
<field name="to_email_contact" |
||||
|
attrs="{'invisible': [('to_email_contact_check', '=',False)]}"/> |
||||
|
<field name="to_email_applicant" |
||||
|
attrs="{'invisible': [('to_email_applicant_check', '=',False)]}"/> |
||||
|
<field name="to_email" invisible="1"/> |
||||
|
<field name="company_name" invisible="1"/> |
||||
|
<field name="recipient_name" invisible="1"/> |
||||
|
<field name="email_finder" invisible="1"/> |
||||
|
<field name="from_email"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="error_check" invisible="1"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<button string="Bounce Check" name="bounce_check" type="object" |
||||
|
attrs="{'invisible': [('error_check', '=',True)]}"/> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
<notebook> |
||||
|
<page string="Messages"> |
||||
|
<field name="bounce_msg" widget="text" attrs="{'invisible': [('error_check', '=',True)]}"/> |
||||
|
<field name="error_msg" widget="text" attrs="{'invisible': [('error_check', '=',False)]}"/> |
||||
|
</page> |
||||
|
</notebook> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id='send_emails_search' model='ir.ui.view'> |
||||
|
<field name="name">send.emails.search</field> |
||||
|
<field name="model">email.api</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<search string="Send Emails"> |
||||
|
<field name="name"/> |
||||
|
<field name="to_email"/> |
||||
|
<field name="send_date"/> |
||||
|
<field name="state"/> |
||||
|
<group expand="1" string="Group By"> |
||||
|
<filter name="groupby_name" context="{'group_by': 'name'}" string="Name"/> |
||||
|
<filter name="groupby_state" context="{'group_by': 'state'}" |
||||
|
string="Email State"/> |
||||
|
</group> |
||||
|
</search> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="email_sending_menu" |
||||
|
parent="mass_mailing.menu_mass_mailing_report" |
||||
|
name="SendGrid Send Emails" |
||||
|
action="email_sending_action"/> |
||||
|
|
||||
|
<record id="email_details_action" model="ir.actions.act_window"> |
||||
|
<field name="name">Email Details</field> |
||||
|
<field name="res_model">email.sent</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="help" type="html"> |
||||
|
<p class="oe_view_nocontent_create">Create Email Details |
||||
|
</p> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="email_details_tree_view" model="ir.ui.view"> |
||||
|
<field name="name">Email Details tree</field> |
||||
|
<field name="model">email.sent</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Email Details"> |
||||
|
<field name="name"/> |
||||
|
<field name="email_id"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="email_details_from_view" model="ir.ui.view"> |
||||
|
<field name="name">Email Details Form</field> |
||||
|
<field name="model">email.sent</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Email Details"> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<field name="name"/> |
||||
|
<field name="email_id"/> |
||||
|
</group> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="email_details_menu" |
||||
|
parent="mass_mailing.mass_mailing_configuration" |
||||
|
name="SendGrid From Email" |
||||
|
action="email_details_action"/> |
||||
|
|
||||
|
<record id="email_template_action" model="ir.actions.act_window"> |
||||
|
<field name="name">Email Template Details</field> |
||||
|
<field name="res_model">email.template</field> |
||||
|
<field name="view_mode">tree,form</field> |
||||
|
<field name="help" type="html"> |
||||
|
<p class="oe_view_nocontent_create">Create Email Template Details |
||||
|
</p> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="email_template_details_tree_view" model="ir.ui.view"> |
||||
|
<field name="name">Email Template Details tree</field> |
||||
|
<field name="model">email.template</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<tree string="Email Template Details"> |
||||
|
<field name="temp_name"/> |
||||
|
<field name="generation"/> |
||||
|
</tree> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="email_template_details_from_view" model="ir.ui.view"> |
||||
|
<field name="name">Email Template Details Form</field> |
||||
|
<field name="model">email.template</field> |
||||
|
<field name="arch" type="xml"> |
||||
|
<form string="Email Template Details"> |
||||
|
<sheet> |
||||
|
<group> |
||||
|
<field name="temp_name"/> |
||||
|
<field name="generation"/> |
||||
|
</group> |
||||
|
<group> |
||||
|
<field name="ver_name"/> |
||||
|
<field name="ver_editor"/> |
||||
|
</group> |
||||
|
<notebook> |
||||
|
<page string="Email Content"> |
||||
|
<label for="ver_subject"/> |
||||
|
<h2 style="display: inline-block;"> |
||||
|
<field name="ver_subject" placeholder="Subject (placeholders may be used here)"/> |
||||
|
</h2> |
||||
|
<field name="temp_cont" widget="html" options="{'style-inline': true}"/> |
||||
|
<button string="Create Template" name="create_temp" type="object"/> |
||||
|
<group> |
||||
|
<field name="temp_id"/> |
||||
|
</group> |
||||
|
<button string="Create Version" name="create_ver" type="object"/> |
||||
|
</page> |
||||
|
</notebook> |
||||
|
</sheet> |
||||
|
</form> |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<record id="action_auto_sent_error_emails" model="ir.actions.server"> |
||||
|
<field name="name">Resend Error Mails</field> |
||||
|
<field name="type">ir.actions.server</field> |
||||
|
<field name="state">code</field> |
||||
|
<field name="model_id" ref="model_email_api"/> |
||||
|
<field name="binding_model_id" ref="model_email_api"/> |
||||
|
<field name="binding_view_types">list</field> |
||||
|
<field name="code"> |
||||
|
records.send_error_mails() |
||||
|
</field> |
||||
|
</record> |
||||
|
|
||||
|
<menuitem id="email_template_details_menu" |
||||
|
parent="mass_mailing.mass_mailing_configuration" |
||||
|
name="SendGrid Template Details" |
||||
|
action="email_template_action"/> |
||||
|
|
||||
|
</data> |
||||
|
</odoo> |