Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev/core#85 On some servers mail() fails when 'Cc' or 'Bcc' headers are defined but empty #12036

Merged
merged 1 commit into from
May 21, 2018

Conversation

mattwire
Copy link
Contributor

Overview

On some servers the PHP mail() function fails to send email if empty 'Cc' or 'Bcc' headers are set.

dev/core#85

Before

Mail cannot be sent, PHP mail() returns false (no error message).

After

Mail is sent, PHP mail() sends.

Technical Details

'Cc' and 'Bcc' headers are optional. Most servers will just ignore them if empty but some seem to fail if they are present but have no email addresses. So we unset them if empty.

@eileenmcnaughton
Copy link
Contributor

@mattwire how can make this as specific as possible to keep the risk as low as possible

I see in the class this ominous block (which @twomice was last to touch)

    // CRM-3795, CRM-7355, CRM-7557, CRM-9058, CRM-9887, CRM-12883, CRM-19173 and others ...
    // The PEAR library requires different parameters based on the mailer used:
    // * Mail_mail requires the Cc/Bcc recipients listed ONLY in the $headers variable
    // * All other mailers require that all be recipients be listed in the $to array AND that
    //   the Bcc must not be present in $header as otherwise it will be shown to all recipients
    // ref: https://pear.php.net/bugs/bug.php?id=8047, full thread and answer [2011-04-19 20:48 UTC]
    if (get_class($mailer) != "Mail_mail") {
      // get emails from headers, since these are
      // combination of name and email addresses.
      if (!empty($headers['Cc'])) {
        $to[] = CRM_Utils_Array::value('Cc', $headers);
      }
      if (!empty($headers['Bcc'])) {
        $to[] = CRM_Utils_Array::value('Bcc', $headers);
        unset($headers['Bcc']);
      }
    }

I think that is the same mailer & we could possibly do this within that block - which has the added benefit we KNOW empty headers are OK for mail_Mail

@@ -289,6 +289,14 @@ public static function send(&$params) {

if (is_object($mailer)) {
$errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
// On some servers mail() fails when 'Cc' or 'Bcc' headers are defined but empty.
// FIXME: Can we unset Cc/Bcc headers for all mail backends if they are empty?
if (empty($headers['Cc'])) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mattwire how about moving this code up i.e. point where it is been initialised

- $headers['Cc'] = CRM_Utils_Array::value('cc', $params);
- $headers['Bcc'] = CRM_Utils_Array::value('bcc', $params);

+ foreach (['Cc', 'Bcc'] as $fieldPart) {
+  if (!empty($params[$fieldPart])) {
+    $headers[$fieldPart] = $params[$fieldPart];
+  }
+ }

and then we no longer this code

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@monishdeb That makes sense. The only issue, which @eileenmcnaughton has also mentioned, is how we make this low risk as most servers are happy with the empty headers, but clearly some are not! Could we end up in a situation where we apply this patch and find that some servers actually require the empty headers? :-(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right most conservative possible plse

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@monishdeb I think it' safe too - but it still scares me

@eileenmcnaughton
Copy link
Contributor

Also noting some confirmation in the wild - https://issues.civicrm.org/jira/browse/CRM-21801

@mattwire
Copy link
Contributor Author

mattwire commented May 6, 2018

@eileenmcnaughton @monishdeb I've updated this PR with the changes suggested by @monishdeb Will post to dev list for feedback.


// On some servers mail() fails when 'Cc' or 'Bcc' headers are defined but empty.
foreach (['Cc', 'Bcc'] as $optionalHeader) {
if (!empty($params[$optionalHeader])) {
Copy link
Contributor

@nganivet nganivet May 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be:

if (!empty($params[strtolower($optionalHeader]))) {

since it is $params['cc'] lower case in the lines that you are replacing?

I also do not like moving away from the CRM_Utils_Array functions.

How about doing instead:

foreach (['Cc', 'Bcc'] as $optionalHeader) {
$headers[$optionalHeader] = CRM_Utils_Array::value(strtolower($optionalHeader), $params);
if (empty($headers[$optionalHeader])) {
unset($headers[$optionalHeader])
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nganivet do you have any opinion about the safety of the fix?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the fix is non-functional, so needs to be corrected first. Then it would depend on the downstream library's expectations and behavior: does it require $headers['cc'] to be set, even if empty? is it creating the CC header in the outgoing email if the $headers['cc'] is not set? I have not investigated these questions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK @nganivet those questions are the key ones we need to answer. This patch has changed a few times since created & I agree the current iteration needs to do a strtolower comparison - but we really need to answer the bigger question - ie. we know some mail servers fail on an empty cc / bcc but we don't know if any servers REQUIRE cc / bcc to be set EVEN IF EMPTY

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nganivet Thanks for the feedback, I cleaned the patch up and as you spotted it no longer worked because of the lowercase issue. I've now amended it with changes as you suggested.

Copy link
Member

@monishdeb monishdeb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the final patch and also finds the logic to be safe about not setting cc and bcc attribute. Hence approving this PR

@eileenmcnaughton
Copy link
Contributor

Per @monishdeb comments in gitlab - this seems fairly compelling https://www.drupal.org/project/mimemail/issues/960374
Merging

@eileenmcnaughton eileenmcnaughton merged commit 42c4823 into civicrm:master May 21, 2018
@mattwire mattwire deleted the mail_unsetcc branch September 25, 2018 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants