Reputation: 1437
I am using Horde IMAP Client to fetch emails from an IMAP server. So far so good, I can authenticate, connect to a mailbox, download and parse emails.
The problem now is I need to parse emails with attachments, and I am finding it a bit tricky figuring out how to set the fetch query, then fetch and get access to email attachments.
I have tried searching the web but not much info on how to use Horde IMAP Client is available on the net, and their documentation is not helping at all.
How can I fetch the attachments from an email?
Here is the code I am using to fetch the envelope details, and plain-text emails from a mailbox (using Composer, rather than PEAR, hence the autoload
):
<?php
// Init
require_once('./vendor/autoload.php');
echo '<pre>';
// Function: Returns a comma-separated list of names and email addresses from a Horde_Mail_Rfc822_List object
function get_parties($addresses) {
$parties = [];
foreach($addresses as $address){
$name = trim($address->personal, "'") ;
$email = $address->bare_address;
$parties[] = $name ? "$name ($email)" : $email;
}
return implode(', ', $parties);
}
// Connect to IMAP
try {
$client = new Horde_Imap_Client_Socket(array(
'username' => '[email protected]',
'password' => 'S0m3PASS',
'hostspec' => 'mygreat.webhost.com',
'port' => '143',
'secure' => 'tls'
));
}
// Failed to connect
catch (Horde_Imap_Client_Exception $e) {
echo "<H1>ERROR!!</H1>";
}
// Search for messages in the Inbox
$query = new Horde_Imap_Client_Search_Query();
$results = $client->search('INBOX', $query);
// Loop over each email found
foreach($results['match'] as $match) {
$query = new Horde_Imap_Client_Fetch_Query();
$query->envelope();
$query->structure();
$uid = new Horde_Imap_Client_Ids($match);
$list = $client->fetch('INBOX', $query, array('ids' => $uid));
$envelope = $list->first()->getEnvelope();
$subject = $envelope->subject;
$from = get_parties($envelope->from);
$to = get_parties($envelope->to);
$cc = get_parties($envelope->cc);
$timestamp = $envelope->date->getTimestamp();
$bst = date('I', $timestamp) * 3600;
$date = gmdate('d/m/Y H:i', $timestamp + $bst); // If no date is specified in the email header, it will default to now
$part = $list->first()->getStructure();
$id = $part->findBody();
$body = $part->getPart($id);
// Output the envelope details
echo "<h1>$date</h1>" .
"<h1>From: $from</h1>" .
"<h1>To: $to</h1>" .
($cc ? "<h1>CC: $cc</h1>" : '') .
"<h1>$subject</h1>";
// Get the message
$query2 = new Horde_Imap_Client_Fetch_Query();
$query2->bodyPart($id, array(
'decode' => true,
'peek' => true
));
$list2 = $client->fetch('INBOX', $query2, array(
'ids' => $uid
));
$message2 = $list2->first();
$text = $message2->getBodyPart($id);
$body->setContents($text);
echo $text = $body->getContents();
echo '<br><br>';
echo '<H1>ENVELOPE</H1>';
print_r($envelope);
echo '<br><br>';
echo '<H1>STRUCTURE</H1>';
print_r($part);
echo '<hr>';
}
echo '</pre>';
?>
Upvotes: 6
Views: 1707
Reputation:
Basing on this example, I've modified your code as follows:
<!DOCTYPE html>
<html>
<body>
<pre>
<?php
require_once './vendor/autoload.php';
class ImapClient {
protected $mailbox = '';
protected $client = null;
protected $params = array();
public function __construct(array $params) {
$this->params = $params;
}
public function login() {
$this->client = new Horde_Imap_Client_Socket($this->params);
}
public function logout() {
if ($this->client) {
$this->client->close();
}
$this->client = null;
}
public function get_messages($mailbox) {
$this->mailbox = $mailbox;
$query = new Horde_Imap_Client_Search_Query();
$results = $this->client->search($this->mailbox, $query);
$query = new Horde_Imap_Client_Fetch_Query();
$query->envelope();
$query->structure();
return $this->client->fetch($this->mailbox, $query, array('ids' => $results['match']));
}
public function parse_message_envelope(Horde_Imap_Client_Data_Fetch $message) {
$envelope = $message->getEnvelope();
$msghdr = new StdClass;
$msghdr->recipients = $envelope->to->bare_addresses;
$msghdr->senders = $envelope->from->bare_addresses;
$msghdr->cc = $envelope->cc->bare_addresses;
$msghdr->subject = $envelope->subject;
$msghdr->timestamp = $envelope->date->getTimestamp();
return $msghdr;
}
public function parse_message_parts(Horde_Imap_Client_Data_Fetch $message) {
// We need the structure at various points below.
$structure = $message->getStructure();
// Now fetch the rest of the message content.
$query = new Horde_Imap_Client_Fetch_Query();
$query->fullText();
// Fetch all of the message parts too.
$typemap = $structure->contentTypeMap();
foreach ($typemap as $part => $type) {
// The body of the part - attempt to decode it on the server.
$query->bodyPart($part, array(
'decode' => true,
'peek' => true,
));
$query->bodyPartSize($part);
}
$id = new Horde_Imap_Client_Ids($message->getUid());
$messagedata = $this->client->fetch($this->mailbox, $query, array('ids' => $id))->first();
// Store the data for this message.
$msgdata = new StdClass;
$msgdata->id = $message->getUid();
$msgdata->contentplain = '';
$msgdata->contenthtml = '';
$msgdata->attachments = array(
'inline' => array(),
'attachment' => array(),
);
$plainpartid = $structure->findBody('plain');
$htmlpartid = $structure->findBody('html');
foreach ($typemap as $part => $type) {
// Get the message data from the body part, and combine it with the structure to give a fully-formed output.
$stream = $messagedata->getBodyPart($part, true);
$partdata = $structure->getPart($part);
$partdata->setContents($stream, array('usestream' => true));
if ($part == $plainpartid) {
$msgdata->contentplain = $partdata->getContents();
} else if ($part == $htmlpartid) {
$msgdata->contenthtml = $partdata->getContents();
} else if ($filename = $partdata->getName($part)) {
$disposition = $partdata->getDisposition();
$disposition = ($disposition == 'inline') ? 'inline' : 'attachment';
$attachment = new StdClass;
$attachment->name = $filename;
$attachment->type = $partdata->getType();
$attachment->content = $partdata->getContents();
$attachment->size = strlen($attachment->content);
$msgdata->attachments[$disposition][] = $attachment;
}
}
return $msgdata;
}
}
$params = array(
'username' => '[email protected]',
'password' => 'S0m3PASS',
'hostspec' => 'mygreat.webhost.com',
'port' => '143',
'secure' => 'tls'
);
$client = new ImapClient($params);
try {
$client->login();
} catch (Exception $e) {
die($e->getMessage());
}
// Retrieve the messages
$messages = $client->get_messages('INBOX');
printf("Found %d messages\n", $messages->count());
foreach ($messages as $message) {
$hdr = $client->parse_message_envelope($message);
printf("\nDate: %s\n", date('d/m/Y H:i:s', $hdr->timestamp));
printf("From: %s\n", implode(',', $hdr->senders));
printf("To: %s\n", implode(',', $hdr->recipients));
if (count($hdr->cc)) printf("Cc: %s\n", implode(',', $hdr->cc));
printf("Subject: %s\n", $hdr->subject);
$body = $client->parse_message_parts($message);
//printf("Plain Body: %s\n", $body->contentplain);
//printf("HTML Body: %s\n", $body->contenthtml);
foreach ($body->attachments as $type => $attachments) {
if (count($attachments)) {
foreach ($attachments as $nr => $attachment) {
printf("\n** %s #%d **\n", UCFirst($type), $nr);
printf("\tName: %s\n", $attachment->name);
printf("\tType: %s\n", $attachment->type);
printf("\tSize: %d\n", $attachment->size);
//printf("\tContent: %s\n", base64_encode($attachment->content));
}
}
}
}
$client->logout();
?>
</pre>
</body>
</html>
Upvotes: 3