3

I'm trying to add an attachment to emails that I draft but cannot seem to get it to work. I've tried to follow the examples here and here but without success.

Here's what I'm able to do so far:

  1. Connect to the Exchange server
  2. Open the mailbox
  3. Draft an html email
  4. Append the email to the mailbox and have it render the html correctly. (when using text/html as the content-type). Using anything else displays the html as plaintext.

As an additional note, after being drafted, the emails are appended to a mailbox on an Exchange 2010 server and are viewed then sent via Outlook 2010.

Below is my mailer class and the code to draft the email.

mailer.php

<?php

class mailer
{
    const USER      =   'user';
    const PASSWORD  =   'pass';
    const MAILBOX   =   '{conn}DRAFTS';

    // STRING ORDER: $content-type . $from . $to . $cc . $subject . "\r\n\r\n" . $message
    public $message;
    public $imap_conn;
    public $boundary;

    function __construct()
    {
        // Open the message property so we can start appending strings.
        $this->message = '';

        // Open the IMAP connection
        $this->imap_conn = imap_open(self::MAILBOX,self::USER,self::PASSWORD);
    }

    public function content_type($string_type)
    {
        $this->message .= "Content-type:{$string_type}\r\n";
    }

    public function from($string_from)
    {
        $this->message .= "From:{$string_from}\r\n";
    }

    public function to($string_to)
    {
        $this->message .= "To:{$string_to}\r\n";
    }

    public function cc($string_cc)
    {
        $this->message .= "Cc:{$string_cc}\r\n";
    }

    public function mime($float_mime_version)
    {
        $this->message .= "MIME-Version:{$float_mime_version}\r\n";
    }

    public function subject($string_subject)
    {
        $this->message .= "Subject:{$string_subject}\r\n\r\n";
    }

    public function message($string_message)
    {
        $this->message .= "{$string_message}\r\n";
    }

    public function set_boundary($string_boundary)
    {
        $this->boundary = $string_boundary;
    }

    public function append()
    {
        imap_append($this->imap_conn,self::MAILBOX,$this->message,"\\Draft");
        imap_close($this->imap_conn);
    }
}

?>

Draft code

// A random hash used for the boundary
$rh = md5(date('c',time()));
$data = chunk_split(base64_encode('Testing'));


$m = new mailer;
$m->set_boundary('--PHP-mixed-' . $rh);
$m->content_type('multipart/mixed; boundary="' . $m->boundary . '"');
$m->mime('1.0');
$m->from('from@mail.com');
$m->to('to@mail.com');
$m->cc('cc1@mail.com,cc2@mail.com');
$m->subject('A new email');
$m->message("
    {$m->boundary}
    Content-Type: text/html; charset=\"utf-8\"
    Content-Transfer-Encoding: base64

    Testing my <b>HTML</b>
    </br>
    {$m->boundary}
    Content-Type: application/octet-stream; name=\"test.txt\"
    Content-Transfer-Encoding: base64
    Content-Disposition: attachment; filename=\"test.txt\"

    {$data}
    {$m->boundary}--
    "));
$m->append();

The message before its appended

Content-type:multipart/mixed; boundary="--PHP-mixed-b408f941593cf92b5a8bd365abb4e64f"
MIME-Version:1.0
From:from@mail.com
To:to@mail.com
Cc:cc1@mail.com
Subject:New Message


            --PHP-mixed-b408f941593cf92b5a8bd365abb4e64f
            Content-Type: text/html; charset="utf-8"
            Content-Transfer-Encoding: "base64"

            My <b>html</b> content



            --PHP-mixed-b408f941593cf92b5a8bd365abb4e64f
            Content-Type: application/octet-stream; name="test.txt"
            Content-Transfer-Encoding: base64
            Content-Disposition: attachment; filename="test.txt"



            --PHP-mixed-b408f941593cf92b5a8bd365abb4e64f--
Community
  • 1
  • 1
Chad
  • 714
  • 2
  • 9
  • 26

2 Answers2

1

Question: How do I add an attachment to an email drafted with PHP via IMAP?

Answer: In short, the issue was in two places.

  1. Improper placement of newlines (\r\n). A single newline should be after each header and two newlines after each ending header of a section. See Figure 1.

  2. Improper boundaries. Boundaries should start with -- followed by a unique string. The ending boundary of the message should begin and end with -- See Figure 2

Figure 1

Content-Type: text/html\r\n
Content-Encoding: base64\r\n\r\n
"Message text here."\r\n

Figure 2

--unique
Content-Type: text/html\r\n
Content-Encoding: base64\r\n\r\n
HTML stuff here.\r\n
--unique
Content-Type: application/octet-stream\r\n
Content-Disposition: attachment; filename=\"logs.csv\"\r\n
Content-Transfer-Encoding: base64\r\n\r\n
Attachment(s)\r\n
--unique--

I plan on doing a more in depth write-up on this as it took me a very long time to get it right.

Chad
  • 714
  • 2
  • 9
  • 26
0

It would be helpful to have some more information on your debugging so far. Is the file being read successfully? Does anything make it to the mailbox? It would also help me to see an output of the full message before your final append.

I do not know if this will solve it, but from my successful code and your second example, your message should have an extra filename property, and the values wrapped in quotes.

Content-Type: application/octet-stream; name="test.txt"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="test.txt"
Jordan
  • 147
  • 6
  • Added double quotes and the message text prior to being appended. The file is being read. – Chad Apr 18 '13 at 19:49
  • Hi again - Have you stripped the file from this message to post on SO? I would include some of it at least so we can verify. Does this make it to the mailbox just fine? You may also try removing the tabs from your message code. – Jordan Apr 18 '13 at 21:39
  • I've switched from using a file to just encoding and chunking a string, which hasn't made any change other than the encoded string getting printed in the email when it gets drafted. Also, I modified the message text so there is no unnecessary whitespace. Still no luck. – Chad Apr 19 '13 at 13:29