Updated: Comment #45

Problem/Motivation

Currently, the Mailhandler Fetcher filter plugins operate based on whether an in-reply-to header is set. If so, they assume the mail is intended to be a comment. If not, the mail is assumed to be a node.

This is problematic because there are many reasons why the in-reply-to header might be set, such as if an email is forwarded, or if an email is sent using Amazon Simple Email. Intent cannot be inferred based on this header alone.

Proposed resolution

The filter plugins should be moved to the Mail Comment module, and Mail Comment should check for a signature in the body or headers to determine whether an email is a node or comment. Additionally, we will also need to implement hook_feeds_importer_default_alter() (sic?) in Mail Comment to override the Mailhandler Default importer to use the Node Filter.

Remaining tasks

See above.

This is not a perfect solution, but it's a step forward. See comment #41 for a scenario where this fails. We should open a new issue for that once this first step is resolved.

Original report by @bakr

Scenario:

- Sample two drupal user account emails are:

- An existing mailbox name is: helpdesk@domain.com (tested to work with pop3 and IMAP)

Feeds importer is configured to authenticate using: "fromaddress"

If John directly sends an email to: helpdesk@domain.com; no issue, the feeds importer will digest that mail and authenticate successfully and create a node of it.

Equally wise, the same applies for Marry.

Now, whereas...

If Marry send an email message to John, and then, John forwards that message to the helpdesk; it does not get authenticated, thus, no node is created.

I think is is an old issue.

Comments

bakr’s picture

Have tested the above scenario with both: IMAP and POP3.

Same effect, no luck.

Reference old Issue: #1192516: Why 'Forwarded Messages' Fail Authentication?

We use MS Exchange Server 2010 with SP1

bakr’s picture

Dear Dane,

I understand from the last Issue that my scenario was not reproducible at your mailing environment, which adds a difficulty to trace down the real problem factor.

However, I might hack the module code to insert a few var_dump($variable) statements, that shall reveal what is going under the hood, to help spot the failure point.

If I would do that, what variables would you direct me to diagnose?

Shall print for a you a nicely formatted array representation:

function print_array($aArray) {
 echo '<pre>';
 print_r($aArray);
 echo '</pre>';
}

Thanks and Regards
Bakr

bakr’s picture

Hoping this narrow down will help, I have added the following line below:

drupal_set_message("Parser Thinks mail is empty!");

  /**
   * Implementation of FeedsParser::parse().
   */
 
public function parse(FeedsImportBatch $batch, FeedsSource $source)
{
    $fetched  = $batch->getRaw();
    $mailbox  = $fetched['mailbox'];
    $messages = $fetched['messages'];
    
    
    
    if (!empty($messages)) {
        foreach ($messages as $mid => &$message) {
            $this->authenticate($message, $mailbox);
            
            if ($message['authenticated_uid'] == 0) {
                //  " User was not authenticated");
                module_invoke_all('mailhandler_auth', 'auth_failed', $message);
                $source_config = $source->getConfigFor($this);
                
                switch ($source_config['if_auth_fails']) {
                    case 'remove':
                        if ($class = mailhandler_plugin_load_class('mailhandler', $mailbox->settings['retrieve'], 'retrieve', 'handler')) {
                            $class->purge_message($mailbox, $message);
                        }
                    case 'retry':
                        throw new Exception('User could not be authenticated. Please check your Mailhandler authentication plugin settings.');
                    case 'unpublish':
                        if ($class = mailhandler_plugin_load_class('mailhandler', $mailbox->settings['retrieve'], 'retrieve', 'handler')) {
                            $class->purge_message($mailbox, $message);
                        }
                        $message['status'] = 0;
                        break;
                    case 'ignore':
                        if ($class = mailhandler_plugin_load_class('mailhandler', $mailbox->settings['retrieve'], 'retrieve', 'handler')) {
                            $class->purge_message($mailbox, $message);
                        }
                        $this->commands($message, $source);
                        break;
                }
            } else {
                if ($class = mailhandler_plugin_load_class('mailhandler', $mailbox->settings['retrieve'], 'retrieve', 'handler')) {
                    $class->purge_message($mailbox, $message);
                }
                $this->commands($message, $source);
                
            }
        }
        $batch->setItems($messages);
        
    } else {
        if (isset($fetched['new'])) {
            drupal_set_message('No new messages.');
        }
		else
		{
++++			drupal_set_message("Parser Thinks Mail is Empty!");
		}
    }
}

Keep in mind, that currently I have to (legitamte) mail messages waiting to be handled by mailhandler, in the it.helpdesk mailbox.

I can send the php header dump

bakr’s picture

Title: Fail to Authenticate "Forwarded" messages. » Fail to Authenticate "Forwarded" messages. (Parser Thinks mail is empty!)
Component: Code » Mailhandler
danepowell’s picture

Title: Fail to Authenticate "Forwarded" messages. (Parser Thinks mail is empty!) » Authentication failing with forwarded messages
Status: Active » Postponed (maintainer needs more info)

What happens if you edit the Mailbox (not the importer, but the mailbox configuration) and set "From header" to "Sender"?

It would help troubleshoot if you could apply the attached patch, and submit the two messages from the dblog after an import.

Anecdotally, I've seen similar failure modes (empty messages) if the headers of an mbox are malformed. Presumably this could happen for IMAP/POP3 connections as well.

danepowell’s picture

StatusFileSize
new685 bytes

Forgot the patch- also, just realized this is for 7.x, but you should be able to apply the changes manually if need be. Very simple.

bakr’s picture

Watchdog returned empty variable strings.

Alternativaly,
I have produced my own header printout, below you will find the headers of two messages,
- the first one, was sent directly to the mailhanlder.
- the other one(was forwarded), still resides in the mail box, and gets unoticed by mailhanlder.

The ration here is to give your wisdom a glimpse into what is happening, such you might catch the malformed spotty area


==================================================================
// THE FOLLOWING IS NORMAL MESSAGE HEADER DUMP -- NO ISSUE WITH IT :-)
==================================================================

stdClass Object
(
    [date] => Fri, 16 Dec 2011 03:23:06 +0400
    [Date] => Fri, 16 Dec 2011 03:23:06 +0400
    [subject] => direct test
    [Subject] => direct test
    [message_id] => <528E3B841BE4A049AE57E9508550FF005FBAD02A@...>
    [toaddress] => IT Helpdesk 
    [to] => Array
        (
            [0] => stdClass Object
                (
                    [personal] => IT Helpdesk
                    [mailbox] => IT.Helpdesk
                    [host] => domain.com
                )

        )

    [fromaddress] => Bakr Mustafa 
    [from] => Array
        (
            [0] => stdClass Object
                (
                    [personal] => Bakr Mustafa
                    [mailbox] => Bakr.Mustafa
                    [host] => domain.com
                )

        )

    [reply_toaddress] => Bakr Mustafa 
    [reply_to] => Array
        (
            [0] => stdClass Object
                (
                    [personal] => Bakr Mustafa
                    [mailbox] => Bakr.Mustafa
                    [host] => domain.com
                )

        )

    [senderaddress] => Bakr Mustafa 
    [sender] => Array
        (
            [0] => stdClass Object
                (
                    [personal] => Bakr Mustafa
                    [mailbox] => Bakr.Mustafa
                    [host] => domain.com
                )

        )

    [Recent] => N
    [Unseen] =>  
    [Flagged] =>  
    [Answered] =>  
    [Deleted] =>  
    [Draft] =>  
    [Msgno] =>    4
    [MailDate] => 16-Dec-2011 03:23:06 +0400
    [Size] => 1088
    [udate] => 1323991386
)
==================================================================
// THE FOLLOWING IS THE APPARENTLY MALFORMED FORWARDED MESSAGE HEADER DUMP
==================================================================
1stdClass Object
(
    [date] => Thu, 15 Dec 2011 10:34:02 +0400
    [Date] => Thu, 15 Dec 2011 10:34:02 +0400
    [subject] => RE: An IT Form is Pending Your Approval
    [Subject] => RE: An IT Form is Pending Your Approval
    [in_reply_to] => <2836d867-2071-4f1a-be7c-7904502db807@...>
    [message_id] => <9B46C58C0404A1429C605EAFCFF6904479D94FF6@...>
    [references] => <2836d867-2071-4f1a-be7c-7904502db807@...>
    [toaddress] => IT Helpdesk 
    [to] => Array
        (
            [0] => stdClass Object
                (
                    [personal] => IT Helpdesk
                    [mailbox] => IT.Helpdesk
                    [host] => domain.com
                )

        )

    [fromaddress] => Paul Green 
    [from] => Array
        (
            [0] => stdClass Object
                (
                    [personal] => Paul Green
                    [mailbox] => Paul.Green
                    [host] => domain.com
                )

        )

    [reply_toaddress] => Paul Green 
    [reply_to] => Array
        (
            [0] => stdClass Object
                (
                    [personal] => Paul Green
                    [mailbox] => Paul.Green
                    [host] => domain.com
                )

        )

    [senderaddress] => Paul Green 
    [sender] => Array
        (
            [0] => stdClass Object
                (
                    [personal] => Paul Green
                    [mailbox] => Paul.Green
                    [host] => domain.com
                )

        )

    [Recent] => N
    [Unseen] =>  
    [Flagged] =>  
    [Answered] =>  
    [Deleted] =>  
    [Draft] =>  
    [Msgno] =>    3
    [MailDate] => 15-Dec-2011 10:34:02 +0400
    [Size] => 44256
    [udate] => 1323930842
)

bakr’s picture

The following is the script I used to generate the above



$authhost="......";
$user="......";
$pass="......";

if ($mbox=imap_open( $authhost, $user, $pass ))
        {
         echo "<h1>Connected to:</h1>\n".$authhost;
         
        } else
        {
         echo "<h1>FAIL!</h1>\n";
        }
echo "<hr size=1>";
		
$inbox = imap_open($authhost,$user,$pass,NULL,1) or die('Cannot connect to Gmail: ' . print_r(imap_errors()));


/* grab emails */
$emails = imap_search($mbox,'ALL');

/* if emails are returned, cycle through each... */
if($emails) {
  
  /* begin output var */
  $output = '';
  
  /* put the newest emails on top */
  rsort($emails);
  
  /* for every email... */
  foreach($emails as $email_number) {
   
    /* get information specific to this email */
    $overview = imap_fetch_overview($inbox,$email_number,0);
	$header   = imap_header($inbox, $email_number); 
    $message  = imap_fetchbody($inbox,$email_number,2);
    

    
    /* output the email body */
    $output.= print_r($header);
    echo $output.'<hr>';
  }
  
  
 
} 

/* close the connection */
imap_close($mbox);

bakr’s picture

I have tried setting "From header" to
- "Sender"
- "From"
-

no luck in three cases so far.

bakr’s picture

By the way..

Even inserting the:

watchdog('mailhandler',"hello");

, proved that it was not even invoked.

the watchdog table was empty.

This indicates the logic is not reaching even here.

function _mailhandler_get_fromaddress($header, $mailbox) {

//***************************************************************************************
 
+++++  watchdog('mailhandler',"hello");
 
  


  if (($fromheader = drupal_strtolower($mailbox->settings['fromheader'])) && isset($header->$fromheader)) {
    $from = $header->$fromheader;
  }
  else {
    $from = $header->from;
  }
  return array($from[0]->mailbox . '@' . $from[0]->host, (isset($from[0]->personal)) ? $from[0]->personal : '');
}

But for sure it got invoked with importing a normal direct message. that is, the watchdog entries where created normally.

bakr’s picture

By the way, I use the mimemail module, does it affect?

To your knowledge, Is it different from phpmailer?

bakr’s picture

So, if the $header (as per the patch) returned nothing in the watchdog table; What could be the deeper further step to dig for trouble within the module?

Keep in mind that the ajax test script for connectivity with the mailbox successfully identifies some messages as residing in the mailbox.

somewhere in between their is a "certain" extra exception handling that needs to be taken care to make thing less fragile, and thus eliminate the anecdotal behavior.

Best Regards
Bakr

danepowell’s picture

I have a suspicion... what happens if you go to admin/build/feeds, edit your importer, edit the fetcher, and change the filter from 'nodes' to 'all'?

The full path for that configuration page is $base_url/admin/build/feeds/edit/[importer_name]/settings/MailhandlerFetcher, where [importer_name] is the machine name of your importer.

bakr’s picture

Aha,

After setting the fetcher setting so filter "All", then trying to re-import, the result is the following error.

An error has occurred.
Please continue to the error page
An error occurred. /hd/?q=batch&id=217&op=do
Fatal error: Cannot instantiate abstract class MailhandlerFilters in F:\htdocs\hd\sites\all\modules\mailhandler\mailhandler.module on line 168

Import simply fails.

Hmmm!

bakr’s picture

function mailhandler_plugin_load_class($module, $plugin, $type, $id, $args = NULL) {
  ctools_include('plugins');
  if ($class = ctools_plugin_load_class($module, $type, $plugin, 'handler')) {
	 
++++	var_dump($class);
	
     return new $class($args);
  }
}

the $class variable was pointing to "MailhandlerPhpImapRetrieve"

Now we need to inspect that class file "MailhandlerPhpImapRetrieve.class.php"

I shall inject some var_dumps...

I think we are getting somewhere with this...

bakr’s picture

Ok... looking in the problematic class...

I noticed that in-between I had to restart apache, as php was claiming out of memory... there is a leak here, eventhough I have more than 1GB allocated for PHP - can you imagine!

anyway....

the $new variable dumps the following:

array(4) { [0]=> int(1) [1]=> int(2) [2]=> int(3) [3]=> int(4) }

So ... stepping next ....

bakr’s picture

The following var_dumps where injected (see +++)

 function retrieve($mailbox, $limit = 0, $encoding = 'UTF-8', $filter_name = 'MailhandlerFilters') {
    // This is cast as string in hook_menu, otherwise the url argument would get used.
    $limit = (int) $limit;
    if ($result = $this->open_mailbox((object)$mailbox->settings)) {
      $new = $this->get_unread_messages($result);
	  
+++	  echo " \n\n *** \$new =\n " .  var_dump($new);
	  
    }
    else {
      imap_errors();
      throw new Exception(t('Unable to connect to %mail. Please check the <a href="@mailbox-edit">connection settings</a> for this mailbox.', array('%mail' => $mailbox->mail, '@mailbox-edit' => url('admin/build/mailhandler/list/' . $mailbox->mail . '/edit'))));
    }
    if ($result && !empty($new)) {

+++	  $status = imap_status($result, $mailbox, SA_MESSAGES);
+++	   echo "\n\n *** \$status = " . var_dump($status)  . "\n";
	
+++	  echo "\n\n *** \$result = " . var_dump($result)  . "\n";
	  
		
      $messages = array();
      $retrieved = 0;
     
	  while ($new && (!$limit || $retrieved < $limit)) {

+++      echo "\n\n *** \$retrieved = " . $retrieved . "\n" ;
+++	  echo "\n\n *** \$this = " . var_dump($this) . "\n";

        $message = $this->retrieve_message($result, $mailbox, array_shift($new), $encoding, $filter_name);
		

		
		
        if ($message) {
          $messages[] = $message;
        }
        $retrieved++;
      }
	  
	 
	  
      $this->close_mailbox($result);
      return $messages;
    }
    else {
      $this->close_mailbox($result);
      watchdog('mailhandler', 'Mailbox %mail was checked and contained no new messages.', array('%mail' => $mailbox->admin_title), WATCHDOG_INFO);
    }
  }

and the result error message which appears during import was as such:

An error occurred. /hd/?q=batch&id=221&op=do

string(26) "MailhandlerPhpImapRetrieve" 

array(4) { [0]=> int(1) [1]=> int(2) [2]=> int(3) [3]=> int(4) } 

*** $new = bool(false) 
*** $status = resource(10) of type (imap) 
*** $result = 
*** $retrieved = 0 

object(MailhandlerPhpImapRetrieve)#3970 (0) { } 

*** $this = string(18) "MailhandlerFilters" 

<b>Fatal error</b>: Cannot instantiate abstract class MailhandlerFilters in <b>F:\htdocs\hd\sites\all\modules\mailhandler\mailhandler.module</b> on line <b>174</b><br />

So, no surprise, the failing line is:

$message = $this->retrieve_message($result, $mailbox, array_shift($new), $encoding, $filter_name);

bakr’s picture

Now ...

going to dig some var_dumps into the following function, to see what can be revealed..

function retrieve_message($result, $mailbox, $i, $encoding, $filter_name = 'MailhandlerFilters')

And i think, that because the above function fail unsafely some how, this may elaborate why the upper calls was failing to be instantiated.

hmmm..

bakr’s picture

All recent findings indicate that there is some hidden limitation in the filters handling mechanism.

As you previously recall, that my inbox was having two stale (forwarded) messages. the whole assumption is that they should be digested by the mail handler and cleared from mail server.

Now, something interesting happened, one of them got through, (while I was fiddling with the code), the other did not.

Now I get this error which further leads to the sneaky trouble area, or call it the root cause:

An error occurred. /hd/?q=batch&id=224&op=do 

string(26) "MailhandlerPhpImapRetrieve" 

array(1) { [0]=> int(1) } 

*** $new = bool(false) 
*** $status = resource(10) of type (imap) 
*** $result = 
*** $retrieved = 0 
object(MailhandlerPhpImapRetrieve)#3970 (0) { } 

*** $this = 
*** array_shift($new) = 1 
*** $encoding = 
*** $filter_name = MailhandlerFilters 
string(18) "MailhandlerFilters" 

*** $filter_name = string(18) "MailhandlerFilters" 

<b>Fatal error</b>: Cannot instantiate abstract class MailhandlerFilters in <b>F:\htdocs\hd\sites\all\modules\mailhandler\mailhandler.module</b> on line <b>174</b><br />

Now we are pointing fingers to:

class MailhandlerFilters

bakr’s picture

Status: Postponed (maintainer needs more info) » Needs review

At last it works (Now mailhandler is able to import every message in the mailbox normally, regardless it was forwarded or directly sent), but after commenting the $filter (see below)

 function retrieve_message($result, $mailbox, $i, $encoding, $filter_name = 'MailhandlerFilters') {
	  
	
    $header = imap_header($result, imap_msgno($result, $i));
	
	drupal_set_message( "\n\n *** \$header = " . print_r($header) . "\n\n\n\n" );
	
	
    // Check to see if we should retrieve this message at all
/*     if ($filter =  mailhandler_plugin_load_class('mailhandler', $filter_name, 'filters', 'handlers')) {
	
      if (!$filter->fetch($header)) {
		 
        return FALSE;
	
      }
	  
...
...
...

Ration is, this is indeed in need of some review of the filtering.

Ofcourse this is not a solution, but a lead.

The filtering was creating all the issue in the up-chain of mailhandler funtion.

bakr’s picture

Title: Authentication failing with forwarded messages » Message Filtering Can Fail Mailhanlder Function(sometimes)

Status: Needs review » Needs work

The last submitted patch, mailhandler-debug.patch, failed testing.

bakr’s picture

Status: Needs work » Needs review

Findings Summary
============

  • There is no issue at all with the imap library.
  • There is no issue at all with the mail header malformation.
  • There is no issue at all with process of retrieving the content from the mail server.

The following function is the root cause of trouble, yet I do not know the root of the root!

$filter =  mailhandler_plugin_load_class('mailhandler', $filter_name, 'filters', 'handlers'))
  • It fails the import process, whether I use regardless of Fetch Mode: All/Comment/Nodes
  • It also fails the import process whether I choose Mime settings as HTML/Text

The last submitted patch, mailhandler-debug.patch, failed testing.

danepowell’s picture

Status: Needs review » Active

Can you download 2.3? The error related to MailhandlerFilter was fixed there (along with many other bugs)... or you can manually apply the fix at #1369672: Error when using 'All' fetcher filter if you just can't upgrade.

danepowell’s picture

Title: Message Filtering Can Fail Mailhanlder Function(sometimes) » 'Node' filter rejecting forwarded emails
Version: 6.x-2.2 » 6.x-2.3

Anyway, assuming upgrading fixes that error, the real issue is that the Node filter is rejecting the forwarded emails due to the presence of the in-reply-to header.

bakr’s picture

I agree with #26.

That is what is happening.

and yes true the recent fix was a step forward but closing another parallel issue.

I do not know why does the filter reject ... if only i can get to know this.
Also, the filter, as a function is doing great, can't go without it... if it wasn't for this issue.

danepowell’s picture

Hmm, this is turning into a pretty kettle of fish... the original goal of the filters was to separate replies from novel emails, assuming that the novel ones would be 'nodes' and the replies would be 'comments'. However, I now realize that this assumption isn't necessarily safe- for instance, someone could reply to a notification of a node post in order to edit that post. Conversely, someone could compose a fresh email with a cid in the commands in order to post a comment. Granted, these are probably edge cases, but I think they indicate an architectural problem.

Separating replies from non-replies is hard enough, but I'm not really sure how to figure out whether the user is trying to post a node or a comment without forcing them to explicitly specify.

danepowell’s picture

Okay... I think the way to handle this is to run filters after the parser. The condition for a comment will be isset($pid) && isset($nid). The condition for a node will be !isset($pid). Note that the pid/nid could be set by mailcomment, or by a command from the user.

danepowell’s picture

Bah... #29 won't work either- an importer with the Feeds Node Processor would import intended comments as nodes.

I'm not sure if this will get fixed in 6.x-2.4- I just can't figure out a way to solve it that's not hackish... if anyone has suggestions, I'd welcome them.

bakr’s picture

maybe as a short solution, would be to add a checkbox to be added in importer configuration screen, so that to bypass filtering is a message is detected being a "forwarded" message

Am not sure how far this can help.

danepowell’s picture

Marked #1408512: Better node/comment message filters as duplicate. The suggestion there, that I like, is to look for both the in-reply-to header AND a Mail Comment server string. It's still not architecturally ideal, but I think it's better than the current system.

(The reason this isn't 'ideal' is that, theoretically, you could try to post a comment by manually specifying the node id / parent id using the commands system. But this would get classified as a node by the filter proposed here. A strange workflow to be sure, but not completely inconceivable.)

obrienmd’s picture

Wouldn't the current filters also be inappropriate for the theoretical situation, as they would run before the commands are processed and not catch that as a comment?

I have the capability to write patches here (I think), but I see two ways forward and am interested in which way you'd like me to proceed:

1) Move this functionality over to mailcomment (preferred IMHO)
2) Add a submodule to mailhandler which provides this, and requires mailcomment

Or am I off base in thinking these are the only two options with my current proposal (which I agree is subpar but gets us further than the current solution)?

bakr’s picture

My voice goes to option 1: the mailcomment.

This would segregate the issue into workable divide-and-conquer approach.

danepowell’s picture

I also think that both of these filters should go in the Mail Comment module, since they now rely on extracting the Mail Comment message signature.

We will also need to implement hook_feeds_importer_default_alter() (sic?) in Mail Comment to override the Mailhandler Default importer to use the Node Filter.

obrienmd’s picture

Hrm, well perhaps I need to stop trying to convince myself I'm a decent developer. I failed miserably at this last night / this morning. The idea's mature, just needs to be

Note: A simple hack of the MailhandlerFiltersNodes and MailhandlerFiltersComments classes to the effect above did a great job of solving our issue in my limited testing.

obrienmd’s picture

Here is my hackified fetch function from MailhandlerFiltersComments (FiltersNodes is vise-versa on the TRUE and FALSE):

  function fetch($header) {
    // return isset($header->in_reply_to);
    $mailcomment_match = preg_match('/' . variable_get('mailcomment_server_string') . '/', $header->in_reply_to);
    if ($mailcomment_match > 0) {
      return TRUE;
    }
    else {
      return FALSE;
    }
  }
Todd Young’s picture

I am (was) experiencing the same thing and I think I changed the filter to "all" (among other random things) and I think the problem went away... Are we fixed on this one? Am I ok?

Thanks for great work, y'all...

1richards’s picture

Had the same problem and switching Mailhandler Fetcher message filter to "All" resolved this for me.

For reference, I am using a gmail account and Feeds 7.x-2.0-alpha5 and Mailhandler 7.x-2.5

thanks all

Mixologic’s picture

It doesn't seem like a solid architecture to attempt to extrapolate whether or not an email is intended to become either a node or a comment based upon whether or not a general purpose SMTP header is set. There are myriad reasons beyond the use cases here that would cause the 'in-reply-to' header to be set.

In my case, Im using the Amazon Simple Email Service and it sets the in-reply-to header on every email it sends. Im sure other email forwarding services do this as well. So checking if the in-reply-to header in MailHandlerFiltersNodes.class.php seems like its bound to only work in certain use cases and not other.

Additionally, a reply isnt necessarily restricted to creating comments in all use cases either. We're building a Q&A style site, where we have the original question, and answers, and comments on both questions and answers. Replies to the the original question will create Answers, whereas replies to the Answers will create comments.

I think the only way to determine the intent is by setting specific commands in the emails, and not relying on the in-reply-to header to contain any sort of intent.

rob230’s picture

Version: 6.x-2.3 » 7.x-2.x-dev
StatusFileSize
new1.26 KB

I think setting it to 'All' is more of a workaround (avoiding the issue) rather than a solution. The method in #37 makes sense to me so I've tried it and it works. Patch for 7.x-2.x attached for anyone that needs it.

It's not a satisfactory solution though because it assumes the presence of Mail Comment. If you don't have Mail Comment, setting the import filter to 'All' will probably fix it for you since you aren't expecting comments anyway. I can't think of a nice way that would work in both cases.

kscheirer’s picture

Issue summary: View changes
Status: Active » Needs review

Hmm, hard to say where we are with this.

I suppose the preg_match patch helps, but only in certain cases.
Setting the import filter to All works in some cases as well.
Neither provide a solid solution.

Is #35 the preferred approach? In which case we should move this issue to Mail Comment, write a patch against that to provide the 2 filters and hook_feeds_importer_default_alter to change the filter provided by Mailhandler?

#41 seems to indicate that any method using in_reply_to will fail in some cases.

I think the only way to determine the intent is by setting specific commands in the emails, and not relying on the in-reply-to header to contain any sort of intent.

That sounds reasonable. Could that command be added to the default commands, and thereby be easy to disable/configure?

If someone can provide me with a good approach and outline the changes, I'm happy to write the patch!

Status: Needs review » Needs work

The last submitted patch, 42: mailhandler-forwarded-emails-1370286.patch, failed testing.

danepowell’s picture

Issue summary: View changes

I updated the issue summary to include what I see as the path forward here. Let's implement the solution I proposed in #35 as a solution that should cover the vast majority of use cases. Then we can open a new issue to cover edge cases such as #41.

danepowell’s picture

Issue summary: View changes
maedi’s picture

As mentioned In-Reply-To can be set even when the email is not a genuine reply. The original Message-ID also moves from In-Reply-To to the References header in longer email chains.

I think the logic should be to just see if the email has a valid Message-ID in the 'reply headers'. Here's a filtering solution based on a patch I've created for Mail Comment: #2852329: Patch: Better parse Message-ID

class MailhandlerFiltersNodes extends MailhandlerFilters {
  /**
   * Whether or not this email is a new node.
   *
   * @param array $header: Message headers
   * @return bool: TRUE if new ticket, FALSE otherwise
   */
  public function fetch($header) {

    $is_new = TRUE;

    // format: 4 digits and 1 hash divided by dots then an @ symbol then a domain
    // example: <1234.4666.5056.1486965753.aa17604ac1434f792f04f724d2af7ee6@domain>
    $valid_message_id = "/\<(\d+[.]\d+[.]\d+[.]\d+[.]\w+\@[a-zA-Z0-9_\-\.]+\.[a-zA-Z]{2,5})\>/";

    // Email not new if has valid message id
    if (isset($header->in_reply_to) && preg_match($valid_message_id, $header->in_reply_to)) {
      $is_new = FALSE;
    }
    if (isset($header->references) && preg_match($valid_message_id, $header->references)) {
      $is_new = FALSE;
    }

    return $is_new;
  }
}
class MailhandlerFiltersComments extends MailhandlerFilters {
  /**
   * Whether or not this email is a reply.
   *
   * @param array $header: Message headers
   * @return bool: TRUE if ticket reply, FALSE otherwise
   */
  public function fetch($header) {

    $is_reply = FALSE;

    // format: 4 digits and 1 hash divided by dots then an @ symbol then a domain
    // example: <1234.4666.5056.1486965753.bb27604gc1434f792f04f724d2af7ee6@domain>
    $valid_message_id = "/\<(\d+[.]\d+[.]\d+[.]\d+[.]\w+\@[a-zA-Z0-9_\-\.]+\.[a-zA-Z]{2,5})\>/";

    // Email is ticket reply if has valid message id
    if (isset($header->in_reply_to) && preg_match($valid_message_id, $header->in_reply_to)) {
      $is_reply = TRUE;
    }
    if (isset($header->references) && preg_match($valid_message_id, $header->references)) {
      $is_reply = TRUE;
    }

    return $is_ticket_reply;
  }
}

The regex could be generalised to work with without mail comment (the string simplified and a check that the domain is the originating site). Or as mentioned the filter could be moved to Mail Comment. If the other patch gets through then we can reference the regex variable from Mail Comment.