Skip to content
4 changes: 4 additions & 0 deletions CRM/Admin/Form/MailSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ public function buildQuickForm() {
];
$this->add('select', 'is_default', ts('Used For?'), $usedfor);
$this->addField('activity_status', ['placeholder' => FALSE]);

$this->add('checkbox', 'is_contact_creation_disabled_if_no_match', ts('Do not create new contacts when filing emails'));
}

/**
Expand Down Expand Up @@ -146,13 +148,15 @@ public function postProcess() {
'is_ssl',
'is_default',
'activity_status',
'is_contact_creation_disabled_if_no_match',
];

$params = [];
foreach ($fields as $f) {
if (in_array($f, [
'is_default',
'is_ssl',
'is_contact_creation_disabled_if_no_match',
])) {
$params[$f] = CRM_Utils_Array::value($f, $formValues, FALSE);
}
Expand Down
4 changes: 4 additions & 0 deletions CRM/Upgrade/Incremental/sql/5.30.0.mysql.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{* file to handle db changes in 5.30.0 during upgrade *}

ALTER TABLE civicrm_mail_settings
ADD is_contact_creation_disabled_if_no_match TINYINT default 0 not null comment 'If this option is enabled, CiviCRM will not create new contacts when filing emails';
27 changes: 16 additions & 11 deletions CRM/Utils/Mail/EmailProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public static function _process($civiMail, $dao, $is_create_activities) {
try {
$store = CRM_Mailing_MailStore::getStore($dao->name);
}
catch (Exception$e) {
catch (Exception $e) {
$message = ts('Could not connect to MailStore for ') . $dao->username . '@' . $dao->server . '<p>';
$message .= ts('Error message: ');
$message .= '<pre>' . $e->getMessage() . '</pre><p>';
Expand Down Expand Up @@ -226,7 +226,8 @@ public static function _process($civiMail, $dao, $is_create_activities) {
if ($usedfor == 0 || $is_create_activities) {
// if its the activities that needs to be processed ..
try {
$mailParams = CRM_Utils_Mail_Incoming::parseMailingObject($mail);
$createContact = !($dao->is_contact_creation_disabled_if_no_match ?? FALSE);
$mailParams = CRM_Utils_Mail_Incoming::parseMailingObject($mail, $createContact, FALSE);
}
catch (Exception $e) {
echo $e->getMessage();
Expand All @@ -241,16 +242,20 @@ public static function _process($civiMail, $dao, $is_create_activities) {
if (!empty($dao->activity_status)) {
$params['status_id'] = $dao->activity_status;
}
$result = civicrm_api('activity', 'create', $params);

if ($result['is_error']) {
$matches = FALSE;
echo "Failed Processing: {$mail->subject}. Reason: {$result['error_message']}\n";
}
else {
$matches = TRUE;
CRM_Utils_Hook::emailProcessor('activity', $params, $mail, $result);
echo "Processed as Activity: {$mail->subject}\n";
// Create activity if its not empty.
if (!empty($params['subject']) || !empty($params['target_contact_id'])) {
$result = civicrm_api('activity', 'create', $params);

if ($result['is_error']) {
$matches = FALSE;
echo "Failed Processing: {$mail->subject}. Reason: {$result['error_message']}\n";
}
else {
$matches = TRUE;
CRM_Utils_Hook::emailProcessor('activity', $params, $mail, $result);
echo "Processed as Activity: {$mail->subject}\n";
}
}
}

Expand Down
20 changes: 12 additions & 8 deletions CRM/Utils/Mail/Incoming.php
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,12 @@ public function &parse(&$file) {

/**
* @param $mail
* @param $createContact
* @param $requireContact
*
* @return array
*/
public static function parseMailingObject(&$mail) {
public static function parseMailingObject(&$mail, $createContact = TRUE, $requireContact = TRUE) {

$config = CRM_Core_Config::singleton();

Expand All @@ -342,18 +344,18 @@ public static function parseMailingObject(&$mail) {
}

$params['from'] = [];
self::parseAddress($mail->from, $field, $params['from'], $mail);
self::parseAddress($mail->from, $field, $params['from'], $mail, $createContact);

// we definitely need a contact id for the from address
// if we dont have one, skip this email
if (empty($params['from']['id'])) {
if ($requireContact && empty($params['from']['id'])) {
return NULL;
}

$emailFields = ['to', 'cc', 'bcc'];
foreach ($emailFields as $field) {
$value = $mail->$field;
self::parseAddresses($value, $field, $params, $mail);
self::parseAddresses($value, $field, $params, $mail, $createContact);
}

// define other parameters
Expand Down Expand Up @@ -396,8 +398,9 @@ public static function parseMailingObject(&$mail) {
* @param array $params
* @param $subParam
* @param $mail
* @param $createContact
*/
public static function parseAddress(&$address, &$params, &$subParam, &$mail) {
public static function parseAddress(&$address, &$params, &$subParam, &$mail, $createContact = TRUE) {
// CRM-9484
if (empty($address->email)) {
return;
Expand All @@ -408,7 +411,7 @@ public static function parseAddress(&$address, &$params, &$subParam, &$mail) {

$contactID = self::getContactID($subParam['email'],
$subParam['name'],
TRUE,
$createContact,
$mail
);
$subParam['id'] = $contactID ? $contactID : NULL;
Expand All @@ -419,13 +422,14 @@ public static function parseAddress(&$address, &$params, &$subParam, &$mail) {
* @param $token
* @param array $params
* @param $mail
* @param $createContact
*/
public static function parseAddresses(&$addresses, $token, &$params, &$mail) {
public static function parseAddresses(&$addresses, $token, &$params, &$mail, $createContact = TRUE) {
$params[$token] = [];

foreach ($addresses as $address) {
$subParam = [];
self::parseAddress($address, $params, $subParam, $mail);
self::parseAddress($address, $params, $subParam, $mail, $createContact);
$params[$token][] = $subParam;
}
}
Expand Down
77 changes: 43 additions & 34 deletions templates/CRM/Admin/Form/MailSettings.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,62 +9,71 @@
*}
{* this template is used for adding/editing email settings. *}
<div class="crm-block crm-form-block crm-mail-settings-form-block">
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{if $action eq 8}
<div class="messages status no-popup">
{icon icon="fa-info-circle"}{/icon}
{ts}WARNING: Deleting this option will result in the loss of mail settings data.{/ts} {ts}Do you want to continue?{/ts}
</div>
{ts}WARNING: Deleting this option will result in the loss of mail settings data.{/ts} {ts}Do you want to continue?{/ts}
</div>
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
{else}
{else}
<table class="form-layout-compressed">

<tr class="crm-mail-settings-form-block-name"><td class="label">{$form.name.label}</td><td>{$form.name.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Name of this group of settings.{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-name"><td class="label">{$form.name.label}</td><td>{$form.name.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Name of this group of settings.{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-server"><td class="label">{$form.server.label}</td><td>{$form.server.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Name or IP address of mail server machine.{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-server"><td class="label">{$form.server.label}</td><td>{$form.server.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Name or IP address of mail server machine.{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-username"><td class="label">{$form.username.label}</td><td>{$form.username.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Username to use when polling (for IMAP and POP3).{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-username"><td class="label">{$form.username.label}</td><td>{$form.username.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Username to use when polling (for IMAP and POP3).{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-password"><td class="label">{$form.password.label}</td><td>{$form.password.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Password to use when polling (for IMAP and POP3).{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-password"><td class="label">{$form.password.label}</td><td>{$form.password.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Password to use when polling (for IMAP and POP3).{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-localpart"><td class="label">{$form.localpart.label}</td><td>{$form.localpart.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Optional local part (e.g., 'civimail+' for addresses like civimail+s.1.2@example.com).{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-localpart"><td class="label">{$form.localpart.label}</td><td>{$form.localpart.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Optional local part (e.g., 'civimail+' for addresses like civimail+s.1.2@example.com).{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-domain"><td class="label">{$form.domain.label}</td><td>{$form.domain.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Email address domain (the part after @).{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-domain"><td class="label">{$form.domain.label}</td><td>{$form.domain.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Email address domain (the part after @).{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-return_path"><td class="label">{$form.return_path.label}</td><td>{$form.return_path.html}</td><tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Contents of the Return-Path header.{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-return_path"><td class="label">{$form.return_path.label}</td><td>{$form.return_path.html}</td><tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Contents of the Return-Path header.{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-protocol"><td class="label">{$form.protocol.label}</td><td>{$form.protocol.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Name of the protocol to use for polling.{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-protocol"><td class="label">{$form.protocol.label}</td><td>{$form.protocol.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Name of the protocol to use for polling.{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-source"><td class="label">{$form.source.label}</td><td>{$form.source.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Folder to poll from when using IMAP (will default to INBOX when empty), path to poll from when using Maildir, etc..{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-source"><td class="label">{$form.source.label}</td><td>{$form.source.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Folder to poll from when using IMAP (will default to INBOX when empty), path to poll from when using Maildir, etc..{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-is_ssl"><td class="label">{$form.is_ssl.label}</td><td>{$form.is_ssl.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Whether to use SSL for IMAP and POP3 or not.{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-is_ssl"><td class="label">{$form.is_ssl.label}</td><td>{$form.is_ssl.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}Whether to use SSL for IMAP and POP3 or not.{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-is_default"><td class="label">{$form.is_default.label}</td><td>{$form.is_default.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}How this mail account will be used. Only one box may be used for bounce processing. It will also be used as the envelope email when sending mass mailings.{/ts}</td></tr>
<tr class="crm-mail-settings-form-block-is_default"><td class="label">{$form.is_default.label}</td><td>{$form.is_default.html}</td></tr>
<tr><td class="label">&nbsp;</td><td class="description">{ts}How this mail account will be used. Only one box may be used for bounce processing. It will also be used as the envelope email when sending mass mailings.{/ts}</td></tr>

<tr class="crm-mail-settings-form-block-activity_status"><td class="label">{$form.activity_status.label}</td><td>{$form.activity_status.html}</td></tr>
<tr class="crm-mail-settings-form-block-is_contact_creation_disabled_if_no_match"><td class="label">&nbsp;</td><td>{$form.is_contact_creation_disabled_if_no_match.html}{$form.is_contact_creation_disabled_if_no_match.label}</td></tr>

<tr class="crm-mail-settings-form-block-activity_status"><td class="label">&nbsp;</td><td>{$form.activity_status.label}<div>{$form.activity_status.html}</div></td></tr>
</table>
<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
{/if}

<div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
{/if}
</div>

{literal}
<script type="text/javascript">
CRM.$(function($) {
var $form = $('form.{/literal}{$form.formClass}{literal}');
function showActivityStatus() {
$('.crm-mail-settings-form-block-activity_status', $form).toggle($(this).val() === '0');
function showActivityFields() {
var fields = [
'.crm-mail-settings-form-block-activity_status',
'.crm-mail-settings-form-block-is_contact_creation_disabled_if_no_match',
];

$(fields.join(', '), $form).toggle($(this).val() === '0');
}
$('select[name=is_default]').each(showActivityStatus).change(showActivityStatus);
$('select[name="is_default"]').each(showActivityFields).change(showActivityFields);
});
</script>
{/literal}
33 changes: 33 additions & 0 deletions tests/phpunit/CRM/Utils/Mail/EmailProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,37 @@ public function setUpMailing() {
$this->eventQueue = $this->callAPISuccess('MailingEventQueue', 'get', ['api.MailingEventQueue.create' => ['hash' => 'aaaaaaaaaaaaaaaa']]);
}

/**
* Set up mail account with 'Do not create new contacts when filing emails'
* option enabled.
*/
public function setUpDoNotCreateContact() {
$this->callAPISuccess('MailSettings', 'get', [
'api.MailSettings.create' => [
'name' => 'mailbox',
'protocol' => 'Localdir',
'source' => __DIR__ . '/data/mail',
'domain' => 'example.com',
'is_default' => '0',
'is_contact_creation_disabled_if_no_match' => TRUE,
],
]);
}

/**
* Test case email processing when is_non_case_email_skipped is enabled.
*/
public function testInboundProcessingDoNotCreateContact() {
$this->setUpDoNotCreateContact();
$mail = 'test_non_cases_email.eml';

copy(__DIR__ . '/data/inbound/' . $mail, __DIR__ . '/data/mail/' . $mail);
$this->callAPISuccess('job', 'fetch_activities', []);
$result = civicrm_api3('Contact', 'get', [
'sequential' => 1,
'email' => "from@test.test",
]);
$this->assertTrue(empty($result['values']));
}

}
11 changes: 11 additions & 0 deletions xml/schema/Core/MailSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,15 @@
<type>Select</type>
</html>
</field>
<field>
<name>is_contact_creation_disabled_if_no_match</name>
<type>boolean</type>
<title>Do not create new contacts when filing emails</title>
<default>0</default>
<html>
<type>CheckBox</type>
</html>
<description>If this option is enabled, CiviCRM will not create new contacts when filing emails.</description>
<add>5.30</add>
</field>
</table>