phpmimemailparser

This commit is contained in:
yuri
2016-10-31 11:30:14 +02:00
parent fd76459077
commit 771d58f425
9 changed files with 525 additions and 44 deletions
+17 -13
View File
@@ -64,11 +64,15 @@ class Importer
return $this->filtersMatcher;
}
public function importMessage($message, $assignedUserId = null, $teamsIdList = [], $userIdList = [], $filterList = [], $fetchOnlyHeader = false, $folderData = null, $parserType = 'Zend')
public function importMessage($message, $assignedUserId = null, $teamsIdList = [], $userIdList = [], $filterList = [], $fetchOnlyHeader = false, $folderData = null, $parserType = 'ZendMail')
{
try {
$parser = $message->getParser();
$parserClassName = '\\Espo\\Core\\Mail\\Parsers\\' . $parserType;
$parser = new $parserClassName($this->getEntityManager());
if (get_class($parser) !== $parserClassName) {
$parser = new $parserClassName($this->getEntityManager());
}
$email = $this->getEntityManager()->getEntity('Email');
@@ -105,14 +109,14 @@ class Importer
$email->set('fromString', $parser->getMessageAttribute($message, 'from'));
}
if ($parser->checkMessageAttribute($message, 'replyTo')) {
$email->set('replyToString', $parser->getMessageAttribute($message, 'replyTo'));
if ($parser->checkMessageAttribute($message, 'reply-To')) {
$email->set('replyToString', $parser->getMessageAttribute($message, 'reply-To'));
}
$fromArr = $parser->getAddressListFromMessage($message, 'from');
$toArr = $parser->getAddressListFromMessage($message, 'to');
$ccArr = $parser->getAddressListFromMessage($message, 'cc');
$replyToArr = $parser->getAddressListFromMessage($message, 'replyTo');
$replyToArr = $parser->getAddressListFromMessage($message, 'reply-To');
$email->set('from', $fromArr[0]);
$email->set('to', implode(';', $toArr));
@@ -129,12 +133,12 @@ class Importer
return false;
}
if ($parser->checkMessageAttribute($message, 'messageId') && $parser->getMessageAttribute($message, 'messageId')) {
if ($parser->checkMessageAttribute($message, 'message-Id') && $parser->getMessageAttribute($message, 'message-Id')) {
$messageId = $parser->getMessageMessageId($message);
$email->set('messageId', $messageId);
if ($parser->checkMessageAttribute($message, 'deliveredTo')) {
$email->set('messageIdInternal', $messageId . '-' . $parser->getMessageAttribute($message, 'deliveredTo'));
if ($parser->checkMessageAttribute($message, 'delivered-To')) {
$email->set('messageIdInternal', $messageId . '-' . $parser->getMessageAttribute($message, 'delivered-To'));
}
if (stripos($messageId, '@espo-system') !== false) {
return;
@@ -181,12 +185,12 @@ class Importer
} else {
$email->set('dateSent', date('Y-m-d H:i:s'));
}
if ($parser->checkMessageAttribute($message, 'deliveryDate')) {
if ($parser->checkMessageAttribute($message, 'delivery-Date')) {
try {
$dt = new \DateTime($parser->getMessageAttribute($message, 'deliveryDate'));
$dt = new \DateTime($parser->getMessageAttribute($message, 'delivery-Date'));
if ($dt) {
$deliveryDate = $dt->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s');
$email->set('deliveryDate', $deliveryDate);
$email->set('delivery-Date', $deliveryDate);
}
} catch (\Exception $e) {}
}
@@ -206,8 +210,8 @@ class Importer
$replied = null;
if ($parser->checkMessageAttribute($message, 'inReplyTo') && $parser->getMessageAttribute($message, 'inReplyTo')) {
$arr = explode(' ', $parser->getMessageAttribute($message, 'inReplyTo'));
if ($parser->checkMessageAttribute($message, 'in-Reply-To') && $parser->getMessageAttribute($message, 'in-Reply-To')) {
$arr = explode(' ', $parser->getMessageAttribute($message, 'in-Reply-To'));
$inReplyTo = $arr[0];
$replied = $this->getEntityManager()->getRepository('Email')->where(array(
'messageId' => $inReplyTo
@@ -31,8 +31,6 @@ namespace Espo\Core\Mail\Mail\Storage;
class Imap extends \Zend\Mail\Storage\Imap
{
//protected $messageClass = '\\Espo\\Core\\Mail\\Mail\\Storage\\Message';
public function getIdsFromUID($uid)
{
$uid = intval($uid) + 1;
@@ -44,5 +42,22 @@ class Imap extends \Zend\Mail\Storage\Imap
return $this->protocol->search(array('SINCE "' . $date . '"'));
}
public function getHeaderAndFlags($id, $part = null)
{
$data = $this->protocol->fetch(['FLAGS', 'RFC822.HEADER'], $id);
$header = $data['RFC822.HEADER'];
$flags = [];
foreach ($data['FLAGS'] as $flag) {
$flags[] = isset(static::$knownFlags[$flag]) ? static::$knownFlags[$flag] : $flag;
}
return array(
'flags' => $flags,
'header' => $header
);
}
}
@@ -0,0 +1,137 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Mail;
use \Espo\Entities\Email;
class MessageWrapper
{
private $storage;
private $id;
private $rawHeader = null;
private $rawContent = null;
private $zendMessage = null;
protected $zendMessageClass = '\Zend\Mail\Storage\Message';
protected $fullRawContent = null;
public function __construct($storage = null, $id = null, $parser = null)
{
if ($storage) {
$data = $storage->getHeaderAndFlags($id);
$this->rawHeader = $data['header'];
$this->flagList = $data['flags'];
}
$this->id = $id;
$this->storage = $storage;
$this->parser = $parser;
}
public function setFullRawContent($content)
{
$this->fullRawContent = $content;
}
public function getRawHeader()
{
return $this->rawHeader;
}
public function getParser()
{
return $this->parser;
}
public function checkAttribute($attribute)
{
return $this->getParser()->checkMessageAttribute($this, $attribute);
}
public function getAttribute($attribute)
{
return $this->getParser()->getMessageAttribute($this, $attribute);
}
public function getRawContent()
{
if (is_null($this->rawContent)) {
$this->rawContent = $this->storage->getRawContent($this->id);
}
return $this->rawContent;
}
public function getFullRawContent()
{
if ($this->fullRawContent) {
return $this->fullRawContent;
}
return $this->getRawHeader() . "\n" . $this->getRawContent();
}
public function getZendMessage()
{
if (!$this->zendMessage) {
if ($this->setFullRawContent) {
$this->message = new $this->zendMessageClass([
'handler' => $this->storage,
'raw' => $this->fullRawContent,
'flags' => $this->flagList
]);
} else {
$this->message = new $this->zendMessageClass([
'handler' => $this->storage,
'id' => $this->id,
'headers' => $this->rawHeader,
'flags' => $this->flagList
]);
}
}
return $this->message;
}
public function getFlags()
{
return $this->flagList;
}
public function isFetched()
{
return !!$this->rawHeader;
}
}
@@ -0,0 +1,165 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: http://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Core\Mail\Parsers;
class PhpMimeMailParser
{
private $entityManager;
private $parserHash = array();
public function __construct($entityManager)
{
$this->entityManager = $entityManager;
}
protected function getEntityManager()
{
return $this->entityManager;
}
protected function getParser($message)
{
$key = spl_object_hash($message);
if (!array_key_exists($key, $this->parserHash)) {
$this->parserHash[$key] = new \PhpMimeMailParser\Parser();
$raw = $message->getRawHeader();
if (!$raw) {
$raw = $message->getFullRawContent();
}
$this->parserHash[$key]->setText($raw);
}
return $this->parserHash[$key];
}
protected function loadContent($message)
{
$this->getParser($message);
$raw = $message->getFullRawContent();
$this->getParser($message)->setText($raw);
}
public function checkMessageAttribute($message, $attribute)
{
return $this->getParser($message)->getHeader($attribute) !== false;
}
public function getMessageAttribute($message, $attribute)
{
if (!$this->checkMessageAttribute($message, $attribute)) return null;
return $this->getParser($message)->getHeader($attribute);
}
public function getMessageMessageId($message)
{
return $this->getMessageAttribute($message, 'Message-ID');
}
public function getAddressListFromMessage($message, $type)
{
$addressList = [];
if ($this->checkMessageAttribute($message, $type)) {
$list = $this->getParser($message)->getAddresses($type);
foreach ($list as $address) {
$addressList[] = $address['address'];
}
}
return $addressList;
}
public function fetchContentParts(\Espo\Entities\Email $email, $message)
{
$this->loadContent($message);
$bodyPlain = $this->getParser($message)->getMessageBody('text');
$bodyHtml = $this->getParser($message)->getMessageBody('html');
if ($bodyHtml) {
$email->set('isHtml', true);
$email->set('body', $bodyHtml);
$email->set('bodyPlain', $bodyPlain);
} else {
$email->set('isHtml', false);
$email->set('body', $bodyPlain);
}
if (!$email->get('body') && $email->get('bodyPlain')) {
$email->set('body', $email->get('bodyPlain'));
}
$attachmentObjList = $this->getParser($message)->getAttachments();
$inlineIds = array();
foreach ($attachmentObjList as $attachmentObj) {
$attachment = $this->getEntityManager()->getEntity('Attachment');
$content = $attachmentObj->getContent();
$disposition = $attachmentObj->getContentDisposition();
$attachment = $this->getEntityManager()->getEntity('Attachment');
$attachment->set('name', $attachmentObj->getFileName());
$attachment->set('type', $attachmentObj->getContentType());
if ($disposition == 'inline') {
$attachment->set('role', 'Inline Attachment');
$contentId = $attachmentObj->getContentID();
} else {
$attachment->set('role', 'Attachment');
}
$attachment->set('contents', $content);
$this->getEntityManager()->saveEntity($attachment);
if ($disposition == 'attachment') {
$attachmentsIds = $email->get('attachmentsIds');
$attachmentsIds[] = $attachment->id;
$email->set('attachmentsIds', $attachmentsIds);
} else if ($disposition == 'inline') {
$inlineIds[$contentId] = $attachment->id;
}
}
$body = $email->get('body');
if (!empty($body)) {
foreach ($inlineIds as $cid => $attachmentId) {
if (strpos($body, 'cid:' . $cid) !== false) {
$body = str_replace('cid:' . $cid, '?entryPoint=attachment&amp;id=' . $attachmentId, $body);
} else {
$email->addLinkMultipleId('attachments', $attachmentId);
}
}
$email->set('body', $body);
}
}
}
@@ -29,7 +29,7 @@
namespace Espo\Core\Mail\Parsers;
class Zend
class ZendMail
{
private $entityManager;
@@ -38,18 +38,22 @@ class Zend
$this->entityManager = $entityManager;
}
public function getEntityManager()
protected function getEntityManager()
{
return $this->entityManager;
}
public function checkMessageAttribute($message, $attribute)
{
$message = $message->getZendMessage();
return isset($message->$attribute);
}
public function getMessageAttribute($message, $attribute)
{
$message = $message->getZendMessage();
if (!isset($message->$attribute)) return null;
return $message->$attribute;
@@ -57,6 +61,8 @@ class Zend
public function getMessageMessageId($message)
{
$message = $message->getZendMessage();
if (!isset($message->messageId)) return null;
$messageId = $message->messageId;
@@ -68,6 +74,8 @@ class Zend
public function getAddressListFromMessage($message, $type)
{
$message = $message->getZendMessage();
$addressList = array();
if (isset($message->$type)) {
$list = $this->normilizeHeader($message->getHeader($type))->getAddressList();
@@ -80,6 +88,8 @@ class Zend
public function fetchContentParts(\Espo\Entities\Email $email, $message)
{
$message = $message->getZendMessage();
$inlineIds = array();
if ($message->isMultipart()) {
+44 -10
View File
@@ -225,6 +225,18 @@ class EmailAccount extends Record
$portionLimit = $this->getConfig()->get('personalEmailMaxPortionSize', self::PORTION_LIMIT);
$parserName = 'ZendMail';
if (extension_loaded('mailparse')) {
$parserName = 'PhpMimeMailParser';
}
if ($this->getConfig()->get('emailParser')) {
$parserName = $this->getConfig()->get('emailParser');
}
$parserClassName = '\\Espo\\Core\\Mail\\Parsers\\' . $parserName;
$parser = new $parserClassName($this->getEntityManager());
$monitoredFoldersArr = explode(',', $monitoredFolders);
foreach ($monitoredFoldersArr as $folder) {
$folder = mb_convert_encoding(trim($folder), 'UTF7-IMAP', 'UTF-8');
@@ -288,15 +300,15 @@ class EmailAccount extends Record
$message = null;
$email = null;
try {
$message = $storage->getMessage($id);
if ($message && $emailAccount->get('keepFetchedEmailsUnread')) {
$message = new \Espo\Core\Mail\MessageWrapper($storage, $id, $parser);
if ($message->isFetched() && $emailAccount->get('keepFetchedEmailsUnread')) {
$flags = $message->getFlags();
}
try {
$email = $importer->importMessage($message, null, $teamIdList, [$userId], $filterCollection, $fetchOnlyHeader, $folderData);
} catch (\Exception $e) {
$GLOBALS['log']->error('EmailAccount '.$emailAccount->id.' (Import Message): [' . $e->getCode() . '] ' .$e->getMessage());
}
$importMethodName = 'importWith' . $parserName;
$email = $this->$importMethodName($importer, $emailAccount, $message, $teamIdList, null, [$userId], $filterCollection, $fetchOnlyHeader, $folderData);
if ($emailAccount->get('keepFetchedEmailsUnread')) {
if (is_array($flags) && empty($flags[Storage::FLAG_SEEN])) {
@@ -305,7 +317,7 @@ class EmailAccount extends Record
}
} catch (\Exception $e) {
$GLOBALS['log']->error('EmailAccount '.$emailAccount->id.' (Get Message): [' . $e->getCode() . '] ' .$e->getMessage());
$GLOBALS['log']->error('EmailAccount '.$emailAccount->id.' (Get Message w/ parser '.$parserName.'): [' . $e->getCode() . '] ' .$e->getMessage());
}
if (!empty($email)) {
@@ -318,10 +330,10 @@ class EmailAccount extends Record
if ($k == count($ids) - 1) {
$lastUID = $storage->getUniqueId($id);
if ($message && isset($message->date)) {
if ($email && $email->get('dateSent')) {
$dt = null;
try {
$dt = new \DateTime($message->date);
$dt = new \DateTime($email->get('dateSent'));
} catch (\Exception $e) {}
if ($dt) {
@@ -350,6 +362,28 @@ class EmailAccount extends Record
return true;
}
protected function importWithPhpMimeMailParser($importer, $emailAccount, $message, $teamIdList, $userId = null, $userIdList = [], $filterCollection, $fetchOnlyHeader, $folderData = null)
{
$email = null;
try {
$email = $importer->importMessage($message, $userId, $teamIdList, $userIdList, $filterCollection, $fetchOnlyHeader, $folderData, 'PhpMimeMailParser');
} catch (\Exception $e) {
$GLOBALS['log']->error('EmailAccount '.$emailAccount->id.' (Import Message w/ php-mime-mail-parser): [' . $e->getCode() . '] ' .$e->getMessage());
}
return $email;
}
protected function importWithZendMail($importer, $emailAccount, $message, $teamIdList, $userId = null, $userIdList = [], $filterCollection, $fetchOnlyHeader, $folderData = null)
{
$email = null;
try {
$email = $importer->importMessage($message, $userId, $teamIdList, $userIdList, $filterCollection, $fetchOnlyHeader, $folderData, 'ZendMail');
} catch (\Exception $e) {
$GLOBALS['log']->error('EmailAccount '.$emailAccount->id.' (Import Message w/ zend-mail): [' . $e->getCode() . '] ' .$e->getMessage());
}
return $email;
}
protected function noteAboutEmail($email)
{
if ($email->get('parentType') && $email->get('parentId')) {
+49 -14
View File
@@ -226,6 +226,18 @@ class InboundEmail extends \Espo\Services\Record
$monitoredFolders = 'INBOX';
}
$parserName = 'ZendMail';
if (extension_loaded('mailparse')) {
$parserName = 'PhpMimeMailParser';
}
if ($this->getConfig()->get('emailParser')) {
$parserName = $this->getConfig()->get('emailParser');
}
$parserClassName = '\\Espo\\Core\\Mail\\Parsers\\' . $parserName;
$parser = new $parserClassName($this->getEntityManager());
$portionLimit = $this->getConfig()->get('inboundEmailMaxPortionSize', self::PORTION_LIMIT);
$monitoredFoldersArr = explode(',', $monitoredFolders);
@@ -239,7 +251,6 @@ class InboundEmail extends \Espo\Services\Record
continue;
}
$lastUID = 0;
$lastDate = 0;
if (!empty($fetchData->lastUID->$folder)) {
@@ -288,9 +299,11 @@ class InboundEmail extends \Espo\Services\Record
$message = null;
$email = null;
try {
$message = $storage->getMessage($id);
if ($message && isset($message->from)) {
$fromString = $message->from;
$message = new \Espo\Core\Mail\MessageWrapper($storage, $id, $parser);
if ($message && $message->checkAttribute('from')) {
$fromString = $message->getAttribute('from');
if (preg_match('/MAILER-DAEMON|POSTMASTER/i', $fromString)) {
$toSkip = true;
try {
@@ -301,14 +314,12 @@ class InboundEmail extends \Espo\Services\Record
}
}
if (!$toSkip) {
try {
$email = $importer->importMessage($message, $userId, $teamIdList, $userIdList, $filterCollection, $fetchOnlyHeader);
} catch (\Exception $e) {
$GLOBALS['log']->error('InboundEmail '.$emailAccount->id.' (Import Message): [' . $e->getCode() . '] ' .$e->getMessage());
}
$importMethodName = 'importWith' . $parserName;
$email = $this->$importMethodName($importer, $emailAccount, $message, $teamIdList, $userId, $userIdList, $filterCollection, $fetchOnlyHeader, null);
}
} catch (\Exception $e) {
$GLOBALS['log']->error('InboundEmail '.$emailAccount->id.' (Get Message): [' . $e->getCode() . '] ' .$e->getMessage());
$GLOBALS['log']->error('InboundEmail '.$emailAccount->id.' (Get Message w/ parser '.$parserName.'): [' . $e->getCode() . '] ' .$e->getMessage());
}
try {
@@ -335,10 +346,12 @@ class InboundEmail extends \Espo\Services\Record
}
if ($k == count($ids) - 1) {
if ($message && isset($message->date)) {
$lastUID = $storage->getUniqueId($id);
if ($email && $email->get('dateSent')) {
$dt = null;
try {
$dt = new \DateTime($message->date);
$dt = new \DateTime($email->get('dateSent'));
} catch (\Exception $e) {}
if ($dt) {
@@ -367,6 +380,28 @@ class InboundEmail extends \Espo\Services\Record
return true;
}
protected function importWithPhpMimeMailParser($importer, $emailAccount, $message, $teamIdList, $userId = null, $userIdList = [], $filterCollection, $fetchOnlyHeader, $folderData = null)
{
$email = null;
try {
$email = $importer->importMessage($message, $userId, $teamIdList, $userIdList = [], $filterCollection, $fetchOnlyHeader, $folderData, 'PhpMimeMailParser');
} catch (\Exception $e) {
$GLOBALS['log']->error('InboundEmail '.$emailAccount->id.' (Import Message w/ php-mime-mail-parser): [' . $e->getCode() . '] ' .$e->getMessage());
}
return $email;
}
protected function importWithZendMail($importer, $emailAccount, $message, $teamIdList, $userId = null, $userIdList = [], $filterCollection, $fetchOnlyHeader, $folderData = null)
{
$email = null;
try {
$email = $importer->importMessage($message, $userId, $teamIdList, $userIdList, $filterCollection, $fetchOnlyHeader, $folderData, 'ZendMail');
} catch (\Exception $e) {
$GLOBALS['log']->error('InboundEmail '.$emailAccount->id.' (Import Message w/ zend-mail): [' . $e->getCode() . '] ' .$e->getMessage());
}
return $email;
}
protected function noteAboutEmail($email)
{
if ($email->get('parentType') && $email->get('parentId')) {
@@ -643,9 +678,9 @@ class InboundEmail extends \Espo\Services\Record
} catch (\Exception $e) {}
}
protected function processBouncedMessage(\Zend\Mail\Storage\Message $message)
protected function processBouncedMessage($message)
{
$content = $message->getContent();
$content = $message->getRawContent();
$isHard = false;
if (preg_match('/permanent[ ]*[error|failure]/', $content)) {
+2 -1
View File
@@ -11,7 +11,8 @@
"zordius/lightncandy": "0.*",
"composer/semver": "^1.4",
"zendframework/zend-servicemanager": "^3.1",
"tecnickcom/tcpdf": "^6.2"
"tecnickcom/tcpdf": "^6.2",
"php-mime-mail-parser/php-mime-mail-parser": "^2.5"
},
"autoload": {
"psr-0": {
Generated
+82 -2
View File
@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "46075698dc4d8c1138cae376ebc572c9",
"content-hash": "b941abc20f072ef97ac9ac3f8c53f5c7",
"hash": "bbe970605dccdfcb703299fb5062a97a",
"content-hash": "d8b34e846d35918eeb1cbee0ac16091e",
"packages": [
{
"name": "composer/semver",
@@ -686,6 +686,86 @@
],
"time": "2013-11-23 19:48:39"
},
{
"name": "php-mime-mail-parser/php-mime-mail-parser",
"version": "2.5.0",
"source": {
"type": "git",
"url": "https://github.com/php-mime-mail-parser/php-mime-mail-parser.git",
"reference": "9e4da9b71fa653782fa622ddb4363709aabcb714"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-mime-mail-parser/php-mime-mail-parser/zipball/9e4da9b71fa653782fa622ddb4363709aabcb714",
"reference": "9e4da9b71fa653782fa622ddb4363709aabcb714",
"shasum": ""
},
"require": {
"ext-mailparse": "*",
"php": "^5.4.0 || ^7.0"
},
"replace": {
"exorus/php-mime-mail-parser": "*",
"messaged/php-mime-mail-parser": "*"
},
"require-dev": {
"phpunit/php-token-stream": "^1.3.0",
"phpunit/phpunit": "^4.0 || ^5.0",
"satooshi/php-coveralls": "0.*",
"squizlabs/php_codesniffer": "2.*"
},
"type": "library",
"autoload": {
"psr-4": {
"PhpMimeMailParser\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "bucabay",
"email": "gabe@fijiwebdesign.com",
"homepage": "http://www.fijiwebdesign.com",
"role": "Developer"
},
{
"name": "eXorus",
"email": "exorus.spam@gmail.com",
"homepage": "https://github.com/eXorus/",
"role": "Developer"
},
{
"name": "M.Valinskis",
"email": "M.Valins@gmail.com",
"homepage": "https://code.google.com/p/php-mime-mail-parser",
"role": "Developer"
},
{
"name": "eugene.emmett.wood",
"email": "gene_w@cementhorizon.com",
"homepage": "https://code.google.com/p/php-mime-mail-parser",
"role": "Developer"
},
{
"name": "alknetso",
"email": "alkne@gmail.com",
"homepage": "https://code.google.com/p/php-mime-mail-parser",
"role": "Developer"
}
],
"description": "Fully Tested Mailparse Extension Wrapper for PHP 5.4+",
"homepage": "https://github.com/php-mime-mail-parser/php-mime-mail-parser",
"keywords": [
"MimeMailParser",
"mail",
"mailparse",
"mime"
],
"time": "2016-10-07 16:46:22"
},
{
"name": "psr/log",
"version": "1.0.0",