phpemail-parsingemail-forwarding

How to change a pipe-forwarded email's "From" and "To" section in PHP


I am trying to mask emails. Basically give an email to a client like "RandomName@MyDomain.com" and have it forward "MyRealEmail@MyDomain.com".

I am pipe forwarding the emails to a php script on my server, where I want to use the "To" and "From" to find the real recipient of the message and forward the message to them removing any identifiable information from the Sender (From) section.

I can parse almost all the data right now from the header, but my problem is with the body. The html body portion can vary so much from different origins. Outlook have a <html> and <body> section, while Gmail just has <div>s. Regardless, I get these strange "=" signs in my raw email too, in both text and html sections, like <=div>!

I just want to change the "From" and "To" and keep the rest of the email pretty much exactly as it is so it doesn't have anomalies in its text or html section.

How can I do this? Should I just parse the raw email and change the occurrences of the emails? how can I send it then? or should I remake the email using phpmailer or some other class? how can i get the body correct then?

My hosting provider doesn't have MailParse extension installed, since I have seen some solutions on the site using that extension, so I am having to do this using available extensions in PHP 5.5

UPDATE

I managed to figure out the = issue, it was quoted-printable, so now I am calling quoted_printable_decode() to resolve that issue. Still trying to figure the best way to forward the email after altering the header though.


Solution

  • After a lot of failed attempts, finally have a solution I can live with. The host server didn't want to allow MailParse because it was an issue on their shared hosting environment, so I went with Mail_mimeDecode and Mail_MIME PEAR extensions.

    // Read the message from STDIN
    $fd = fopen("php://stdin", "r");
    $input = "";
    while (!feof($fd)) {
        $input .= fread($fd, 1024);
    }
    fclose($fd);
    
    $params['include_bodies'] = true;
    $params['decode_bodies']  = true;
    $params['decode_headers'] = true;
    $decoder = new Mail_mimeDecode($input);
    $structure = $decoder->decode($params);
    
    // get the header From and To email
    $From = ExtractEmailAddress($structure->headers['from'])[0];
    $To = ExtractEmailAddress($structure->headers['to'])[0];
    $Subject = $structure->headers['subject'];
    

    ExtractEmailAddress uses a solution from "In PHP, how do I extract multiple e-mail addresses from a block of text and put them into an array?"

    For the Body I used the following to find the text and html portions:

    $HTML = "";
    $TEXT = "";
    // extract email body details
    foreach($structure as $K => $V){
        if(is_array($V)){
            foreach($V as $KK => $VV){
                if(is_object($VV)){
                    $bodyHTML = false;
                    $bodyPLAIN = false;
                    foreach($VV as $KKK => $VVV){
                        if(!is_array($VVV)){
                            if($KKK === 'ctype_secondary'){
                                if($VVV === 'html') { $bodyHTML = true; }
                                if($VVV === 'plain') { $bodyPLAIN = true; }
                            }
                            if($KKK === 'body'){
                                if($bodyHTML){
                                    $bodyHTML = false;
                                    $HTML .= quoted_printable_decode($VVV);
                                }
                                if($bodyPLAIN){
                                    $bodyPLAIN = false;
                                    $TEXT .= quoted_printable_decode($VVV);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    

    Finally, I had the parts I needed so I used Mail_MIME to get the message out. I do my database lookup logic here and find the real destination and masked From email address using the From and To I extracted from the header.

    $mime = new Mail_mime(array('eol' => "\r\n"));
    $mime->setTXTBody($TEXT);
    $mime->setHTMLBody($HTML);
    
    $mail = &Mail::factory('mail');
    $hdrs = array(
                  'From'    => $From,
                  'Subject' => $Subject
                  );
    $mail->send($To, $mime->headers($hdrs), $mime->get());
    

    I don't know if this will cover all cases of email bodies, but since my system is not using attachments I am ok for now.

    Take not of quoted_printable_decode(), that how I fixed the issue with the = in the body.

    The only issue is the delay in mail I am having now, but I'll deal with that