diff --git a/application/Espo/Modules/Crm/Controllers/MassEmail.php b/application/Espo/Modules/Crm/Controllers/MassEmail.php index 6a245f25fb..5143a8fc2d 100644 --- a/application/Espo/Modules/Crm/Controllers/MassEmail.php +++ b/application/Espo/Modules/Crm/Controllers/MassEmail.php @@ -68,4 +68,13 @@ class MassEmail extends \Espo\Core\Controllers\Record $this->getRecordService()->processSending($massEmail, true); return true; } + + public function getActionSmtpAccountDataList() + { + if (!$this->getAcl()->checkScope('MassEmail', 'create') && !$this->getAcl()->checkScope('MassEmail', 'edit')) { + throw new Forbidden(); + } + + return $this->getServiceFactory()->create('MassEmail')->getSmtpAccountDataList(); + } } diff --git a/application/Espo/Modules/Crm/Resources/i18n/en_US/MassEmail.json b/application/Espo/Modules/Crm/Resources/i18n/en_US/MassEmail.json index f98f965f6a..7a8d9e9d1d 100644 --- a/application/Espo/Modules/Crm/Resources/i18n/en_US/MassEmail.json +++ b/application/Espo/Modules/Crm/Resources/i18n/en_US/MassEmail.json @@ -13,7 +13,8 @@ "inboundEmail": "Email Account", "targetLists": "Target Lists", "excludingTargetLists": "Excluding Target Lists", - "optOutEntirely": "Opt-Out Entirely" + "optOutEntirely": "Opt-Out Entirely", + "smtpAccount": "SMTP Account" }, "links": { "targetLists": "Target Lists", @@ -35,7 +36,10 @@ }, "labels": { "Create MassEmail": "Create Mass Email", - "Send Test": "Send Test" + "Send Test": "Send Test", + "System SMTP": "System SMTP", + "system": "system", + "group": "group" }, "messages": { "selectAtLeastOneTarget": "Select at least one target.", @@ -44,7 +48,8 @@ "tooltips": { "optOutEntirely": "Email addresses of recipients that unsubscribed will be marked as opted out and they will not receive any mass emails anymore.", "targetLists": "Targets that should receive messages.", - "excludingTargetLists": "Targets that should not receive messages." + "excludingTargetLists": "Targets that should not receive messages.", + "storeSentEmails": "Emails will be stored in CRM." }, "presetFilters": { "actual": "Actual", diff --git a/application/Espo/Modules/Crm/Resources/layouts/MassEmail/detail.json b/application/Espo/Modules/Crm/Resources/layouts/MassEmail/detail.json index bb3fe024bd..a142660d4c 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/MassEmail/detail.json +++ b/application/Espo/Modules/Crm/Resources/layouts/MassEmail/detail.json @@ -21,6 +21,10 @@ [ {"name": "emailTemplate"}, {"name": "storeSentEmails"} ], + [ + {"name": "smtpAccount"}, + false + ], [ {"name": "fromAddress"}, {"name": "fromName"} diff --git a/application/Espo/Modules/Crm/Resources/layouts/MassEmail/detailSmall.json b/application/Espo/Modules/Crm/Resources/layouts/MassEmail/detailSmall.json index 221df9bce6..a42b52b53f 100644 --- a/application/Espo/Modules/Crm/Resources/layouts/MassEmail/detailSmall.json +++ b/application/Espo/Modules/Crm/Resources/layouts/MassEmail/detailSmall.json @@ -24,6 +24,9 @@ {"name": "storeSentEmails"}, {"name": "optOutEntirely"} ], + [ + {"name": "smtpAccount", "fullWidth": true} + ], [ {"name": "fromAddress"}, {"name": "fromName"} diff --git a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/MassEmail.json b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/MassEmail.json index f5359540ba..b6c6f95900 100644 --- a/application/Espo/Modules/Crm/Resources/metadata/entityDefs/MassEmail.json +++ b/application/Espo/Modules/Crm/Resources/metadata/entityDefs/MassEmail.json @@ -12,7 +12,8 @@ }, "storeSentEmails": { "type": "bool", - "default": false + "default": false, + "tooltip": true }, "optOutEntirely": { "type": "bool", @@ -58,6 +59,11 @@ "inboundEmail": { "type": "link" }, + "smtpAccount": { + "type": "base", + "notStorable": true, + "view": "crm:views/mass-email/fields/smtp-account" + }, "createdAt": { "type": "datetime", "readOnly": true diff --git a/application/Espo/Modules/Crm/Services/MassEmail.php b/application/Espo/Modules/Crm/Services/MassEmail.php index 5dd2d2d63c..f39d3d84e8 100644 --- a/application/Espo/Modules/Crm/Services/MassEmail.php +++ b/application/Espo/Modules/Crm/Services/MassEmail.php @@ -309,8 +309,27 @@ class MassEmail extends \Espo\Services\Record } $attachmentList = $emailTemplate->get('attachments'); + $smtpParams = null; + + if ($massEmail->get('inboundEmailId')) { + $inboundEmail = $this->getEntityManager()->getEntity('InboundEmail', $massEmail->get('inboundEmailId')); + if (!$inboundEmail) { + throw new Error("Group Email Account '".$massEmail->get('inboundEmailId')."' is not available."); + } + + if (!$inboundEmail->get('useSmtp') || !$inboundEmail->get('smtpIsForMassEmail')) { + throw new Error("Group Email Account '".$massEmail->get('inboundEmailId')."' can't be used for Mass Email."); + } + + $inboundEmailService = $this->getServiceFactory()->create('InboundEmail'); + $smtpParams = $inboundEmailService->getSmtpParamsFromAccount($inboundEmail); + if (!$smtpParams) { + throw new Error("Group Email Account '".$massEmail->get('inboundEmailId')."' has no SMTP params."); + } + } + foreach ($queueItemList as $queueItem) { - $this->sendQueueItem($queueItem, $massEmail, $emailTemplate, $attachmentList, $campaign, $isTest); + $this->sendQueueItem($queueItem, $massEmail, $emailTemplate, $attachmentList, $campaign, $isTest, $smtpParams); } if (!$isTest) { @@ -390,7 +409,7 @@ class MassEmail extends \Espo\Services\Record return $email; } - protected function sendQueueItem(Entity $queueItem, Entity $massEmail, Entity $emailTemplate, $attachmentList = [], $campaign = null, $isTest = false) + protected function sendQueueItem(Entity $queueItem, Entity $massEmail, Entity $emailTemplate, $attachmentList = [], $campaign = null, $isTest = false, $smtpParams = false) { $queueItemFetched = $this->getEntityManager()->getEntity($queueItem->getEntityType(), $queueItem->id); if ($queueItemFetched->get('status') !== 'Pending') { @@ -458,7 +477,15 @@ class MassEmail extends \Espo\Services\Record $message->getHeaders()->addHeaderLine('List-Unsubscribe', '<' . $optOutUrl . '>'); } - $this->getMailSender()->useGlobal()->send($email, $params, $message, $attachmentList); + $sender = $this->getMailSender(); + + if ($smtpParams) { + $sender->useSmtp($smtpParams); + } else { + $sender->useGlobal(); + } + + $sender->send($email, $params, $message, $attachmentList); $isSent = true; } catch (\Exception $e) { @@ -542,5 +569,32 @@ class MassEmail extends \Espo\Services\Record ); } -} + public function getSmtpAccountDataList() + { + if (!$this->getAcl()->checkScope('MassEmail', 'create') && !$this->getAcl()->checkScope('MassEmail', 'edit')) { + throw new Forbidden(); + } + $dataList = []; + $inboundEmailList = $this->getEntityManager()->getRepository('InboundEmail')->where([ + 'useSmtp' => true, + 'status' => 'Active', + 'smtpIsForMassEmail' => true, + 'emailAddress!=' => '', + 'emailAddress!=' => null + ])->find(); + + foreach ($inboundEmailList as $inboundEmail) { + $item = (object) []; + $key = 'inboundEmail:' . $inboundEmail->id; + $item->key = $key; + $item->emailAddress = $inboundEmail->get('emailAddress'); + $item->fromName = $inboundEmail->get('fromName'); + + $dataList[] = $item; + } + + return $dataList; + } + +} diff --git a/client/modules/crm/src/views/mass-email/fields/smtp-account.js b/client/modules/crm/src/views/mass-email/fields/smtp-account.js new file mode 100644 index 0000000000..59b6dd5df8 --- /dev/null +++ b/client/modules/crm/src/views/mass-email/fields/smtp-account.js @@ -0,0 +1,114 @@ +/************************************************************************ + * This file is part of EspoCRM. + * + * EspoCRM - Open Source CRM application. + * Copyright (C) 2014-2017 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko + * Website: http://www.espocrm.com + * + * EspoCRM is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EspoCRM 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with EspoCRM. If not, see http://www.gnu.org/licenses/. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. + ************************************************************************/ + +Espo.define('crm:views/mass-email/fields/smtp-account', 'views/fields/enum', function (Dep) { + + return Dep.extend({ + + setupOptions: function () { + Dep.prototype.setupOptions.call(this); + + this.params.options = []; + this.translatedOptions = {}; + + this.params.options.push('system'); + + if (!this.loadedOptionList) { + if (this.model.get('inboundEmailId')) { + var item = 'inboundEmail:' + this.model.get('inboundEmailId'); + this.params.options.push(item); + this.translatedOptions[item] = + (this.model.get('inboundEmailName') || this.model.get('inboundEmailId')) + ' (' + this.translate('group', 'labels', 'MassEmail') + ')'; + } + } else { + this.loadedOptionList.forEach(function (item) { + this.params.options.push(item); + this.translatedOptions[item] = + (this.loadedOptionTranslations[item] || item) + ' (' + this.translate('group', 'labels', 'MassEmail') + ')'; + }, this); + } + + this.translatedOptions['system'] = + this.getConfig().get('outboundEmailFromAddress') + ' (' + this.translate('system', 'labels', 'MassEmail') + ')'; + }, + + getValueForDisplay: function () { + if (!this.model.has(this.name)) { + if (this.model.get('inboundEmailId')) { + return 'inboundEmail:' + this.model.get('inboundEmailId'); + } else { + return 'system'; + } + } + + return this.model.get(this.name); + }, + + setup: function () { + Dep.prototype.setup.call(this); + + if (this.getAcl().checkScope('MassEmail', 'create') || this.getAcl().checkScope('MassEmail', 'edit')) { + this.ajaxGetRequest('MassEmail/action/smtpAccountDataList').then(function (dataList) { + if (!dataList.length) return; + this.loadedOptionList = []; + this.loadedOptionTranslations = {}; + this.loadedOptionAddresses = {}; + this.loadedOptionFromNames = {}; + dataList.forEach(function (item) { + this.loadedOptionList.push(item.key); + this.loadedOptionTranslations[item.key] = item.emailAddress; + this.loadedOptionAddresses[item.key] = item.emailAddress; + this.loadedOptionFromNames[item.key] = item.fromName || ''; + }, this); + this.setupOptions(); + this.reRender(); + }.bind(this)); + } + }, + + fetch: function () { + var data = {}; + var value = this.$element.val(); + data[this.name] = value; + + if (!value || value === 'system') { + data.inboundEmailId = null; + data.inboundEmailName = null; + } else { + var arr = value.split(':'); + if (arr.length > 1) { + data.inboundEmailId = arr[1]; + data.inboundEmailName = this.translatedOptions[data.inboundEmailId] || data.inboundEmailId; + } + } + + return data; + } + + }); +}); diff --git a/client/modules/crm/src/views/mass-email/record/edit-small.js b/client/modules/crm/src/views/mass-email/record/edit-small.js index 1d349684e2..381be53da8 100644 --- a/client/modules/crm/src/views/mass-email/record/edit-small.js +++ b/client/modules/crm/src/views/mass-email/record/edit-small.js @@ -26,10 +26,13 @@ * these Appropriate Legal Notices must retain the display of the "EspoCRM" word. ************************************************************************/ -Espo.define('crm:views/mass-email/record/edit-small', 'views/record/edit-small', function (Dep) { +Espo.define('crm:views/mass-email/record/edit-small', ['views/record/edit-small', 'crm:views/mass-email/record/edit'], function (Dep, Edit) { return Dep.extend({ + setup: function () { + Dep.prototype.setup.call(this); + Edit.prototype.initFieldsControl.call(this); + } }); }); - diff --git a/client/modules/crm/src/views/mass-email/record/edit.js b/client/modules/crm/src/views/mass-email/record/edit.js index 7836aa42a1..a73075e994 100644 --- a/client/modules/crm/src/views/mass-email/record/edit.js +++ b/client/modules/crm/src/views/mass-email/record/edit.js @@ -30,6 +30,28 @@ Espo.define('crm:views/mass-email/record/edit', 'views/record/edit', function (D return Dep.extend({ + setup: function () { + Dep.prototype.setup.call(this); + this.initFieldsControl(); + }, + + initFieldsControl: function () { + this.listenTo(this.model, 'change:smtpAccount', function (model, value, o) { + if (!o.ui) return; + + if (!value || value === 'system') { + this.model.set('fromAddress', this.getConfig().get('outboundEmailFromAddress') || ''); + this.model.set('fromName', this.getConfig().get('outboundEmailFromName') || ''); + return; + } + var smtpAccountView = this.getFieldView('smtpAccount'); + if (!smtpAccountView) return; + if (!smtpAccountView.loadedOptionAddresses) return; + if (!smtpAccountView.loadedOptionAddresses[value]) return; + this.model.set('fromAddress', smtpAccountView.loadedOptionAddresses[value]); + this.model.set('fromName', smtpAccountView.loadedOptionFromNames[value]); + }, this); + } + }); }); -