bjc/roundcube-imap

从 roundcubemail 中提取的 PHP imap 客户端类

v0.1.0 2021-11-14 16:49 UTC

This package is auto-updated.

Last update: 2024-09-19 15:04:09 UTC


README

一个用于通过 IMAP 协议读取和处理电子邮件的 PHP IMAP 库。它独立于 PHP IMAP 扩展,并支持 IMAP 协议的新增功能,如 CONDSTORE 和 QRESYNC,这些功能标准 PHP IMAP 扩展不支持。

用于通过 IMAP 协议进行通信的代码是从 roundcubemail 项目(https://roundcube.net/)提取的。访问类/方法的接口受到了 ddeboer/imap(另一个面向对象的 IMAP 库)的启发。

安装

推荐通过 Composer 安装此包。请注意,此包仅在 Composer 2 中可用。如果您仍在运行 Composer 1,您必须升级到 Composer 2。

$ composer require bjc/roundcube-imap

此命令需要您全局安装 Composer,请参阅 Composer 文档中的 安装章节

用法

连接和认证

// $ssl_mode is optional. It can take values "tls", "ssl" and "plain". Default value is "tls".
$server = new \bjc\roundcubeimap\server($host, $ssl_mode);

// $connection is an object of \bjc\roundcubeimap\connection.
$connection = $server->authenticate($username, $password);

邮箱

从邮件服务器检索邮箱(也称为邮件文件夹)并遍历它们

$mailboxes = $connection->getMailboxes();

foreach ($mailboxes as $mailbox) {

  // $mailbox is an object of \bjc\roundcubeimap\mailbox

}

或检索特定的邮箱

$mailbox = $connection->getMailbox('INBOX');

创建邮箱

// true on success, throws \Exception on error
$result = $connection->createMailbox($mailboxname);

重命名邮箱

// true on success, throws \Exception on error
$result = $connection->renameMailbox($mailboxname, $new_mailboxname);

清空邮箱(删除所有邮件)

// true on success, throws \Exception on error
$result = $connection->clearMailbox($mailboxname);

删除邮箱

// true on success, throws \Exception on error
$result = $connection->deleteMailbox($mailboxname);

邮箱状态

要检索邮箱的状态,请运行

$status = $mailbox->getStatus();
// $status is a stdClass object that contains the values uidnext, uidvalidity, recent and if available highestmodseq

邮件

在检索邮件时,了解 UIDs 和 uidvalidity 的概念很重要。UID 是消息在邮箱内的唯一数字标识符(不要与消息 ID 混淆,消息 ID 是一个字母数字标识符,用于标识“全球范围内”的消息)。当将新消息放入邮箱时,它将始终获得比之前所有邮件更高的 UID。因此,当您的应用程序知道它最后获取的 UID 时,它可以轻松地要求 IMAP 服务器仅发送新收到的邮件。只要消息的 UIDs 不变且新消息始终比现有邮件具有更高的 UIDs,这个概念就会起作用。存在一些情况不符合这种情况,这就是 uidvalidity 的原因。Uidvalidity 是 IMAP 服务器为每个邮箱维护的参数。只要此参数保持不变,分配给现有邮件的 UIDs 就没有变化,并且新消息始终比现有邮件具有更高的 UIDs。

因此,您的应用程序必须为每个邮箱存储两个参数

  • uidvalidity
  • 最后获取的 uid

如果您检查邮箱,首先检查 uidvalidity 是否与您在应用程序中存储的相应邮箱的 uidvalidity 相比已更改。如果已更改,请删除应用程序中存储的电子邮件数据(针对此邮箱),并重新获取一切,因为消息的 UIDs 可能已更改。如果 uidvalidity 保持不变,则只需获取比您最后获取的 uid 更高的新邮件。

要获取当前的 uidvalidity 值,请运行

$status = $mailbox->getStatus();
$uidvalidity = $status->uidvalidity;

获取高于特定 UID 的邮件(通常是您最后获取的 UID)

$messagearray = $mailbox->getMessageshigherthan($lastfetcheduid);

foreach ($messagearray as $message) {
  // $message is an object of \bjc\roundcubeimap\message
}

如果您计划分析所有电子邮件的 bodystructure,您现在可以请求获取(并在消息对象中存储)集合中所有邮件的 bodystructure,通过将函数调用中的第二个变量设置为 true 实现

$messagearray = $mailbox->getMessageshigherthan($lastfetcheduid, true);

无论如何,如果需要但尚未存储在消息对象中的bodystructure,消息对象将负责稍后获取。

请注意,上述命令将获取所选消息的标准一组标题。您可以通过在函数调用中添加一个字符串数组作为第三个变量来添加您想要获取的额外标题。

$messagearray = $mailbox->getMessageshigherthan($lastfetcheduid, false, ['X-Spam-Status','X-Mailer']);

获取特定消息集的消息(例如,如果您想再次获取所有消息,因为uidvalidity已更改)

$message_set = '1:*';

$messagearray = $mailbox->getMessageSequence($message_set);

foreach ($messagearray as $message) {
  // $message is an object of \bjc\roundcubeimap\message
}

如果您计划分析所有电子邮件的 bodystructure,您现在可以请求获取(并在消息对象中存储)集合中所有邮件的 bodystructure,通过将函数调用中的第二个变量设置为 true 实现

$messagearray = $mailbox->getMessageSequence($message_set, true);

无论如何,如果需要但尚未存储在消息对象中的bodystructure,消息对象将负责稍后获取。

请注意,上述命令将获取所选消息的标准一组标题。您可以通过在函数调用中添加一个字符串数组作为第三个变量来添加您想要获取的额外标题。

$messagearray = $mailbox->getMessageSequence($message_set, false, ['X-Spam-Status','X-Mailer']);

如果您知道您想要检索的消息的UID

$message = $mailbox->getMessage($uid);
// $message is an object of \bjc\roundcubeimap\message

如果您打算分析电子邮件的bodystructure,您现在就可以通过将函数调用的第二个变量设置为true来请求获取bodystructure(并将其存储在消息对象中)

$messagearray = $mailbox->getMessage($uid, true);

无论如何,如果需要但尚未存储在消息对象中的bodystructure,消息对象将负责稍后获取。

请注意,上述命令将获取所选消息的标准一组标题。您可以通过在函数调用中添加一个字符串数组作为第三个变量来添加您想要获取的额外标题。

$message = $mailbox->getMessage($uid, false, ['X-Spam-Status','X-Mailer']);

检查您的服务器是否能够进行同步(即已实现CONDSTORE和QRESYNC扩展)

同步可以帮助您确保您的应用程序数据与IMAP服务器上的情况保持最新。首先您必须检查您的服务器是否支持它

$condstore = $mailbox->checkCondstore();
// true if condstore is available, false if not

$qresync = $mailbox->checkQresync();
// true if qresync is available, false if not

如果您的服务器支持CONDSTORE和QRESYNC扩展,那么您可以同步您的数据

“同步”意味着您只能获取自上次获取以来已更改、新到达或被删除的消息。为此,您必须在持久化中为每个邮箱存储另一个参数(除了uidvalidity):Highestmodsequence

Highestmodsequence是一个数值,每次邮箱中发生更改时都会增加。IMAP服务器会跟踪哪些更改发生在哪个modsequence,因此当您请求自某个modsequence以来的更改时,它可以告诉您需要通知您哪些更改。

要获取邮箱的当前最高modseq(以便在您的应用程序中存储它,直到您的下一次获取),请运行

$status = $mailbox->getStatus();
$highestmodseq = $status->highestmodseq;

要获取上次同步以来的更改,请运行

$synchronize_result = $mailbox->synchronize($stored_highestmodseq, $stored_uidvalidity);

// check if status == 1 (query worked), if status == 0 check statusmessage to see what went wrong:
$status = $synchronize_result["status"];
$statusmessage = $synchronize_result["statusmesage"];

// Get array of messages
$messagearray = $synchronize_result["messagearray"];

foreach ($messagearray as $message) {
  // $message is an object of \bjc\roundcubeimap\message
}

// get array of vanished (deleted) messages
$vanishedarray = $synchronize_result["vanishedarray"];

foreach ($vanishedarray as $uid) {
  // uid is the uid of the deleted message
}

如果您计划分析电子邮件的bodystructure,您现在就可以通过将函数调用的第三个变量设置为true来请求获取bodystructure(并将其存储在消息对象中)

$messagearray = $mailbox->synchronize($stored_highestmodseq, $stored_uidvalidity, true);

无论如何,如果需要但尚未存储在消息对象中的bodystructure,消息对象将负责稍后获取。

请注意,上述命令将获取所选消息的标准一组标题。您可以通过在函数调用中添加一个字符串数组作为第四个变量来添加您想要获取的额外标题。

$synchronize_result = $mailbox->synchronize($stored_highestmodseq, $stored_uidvalidity, false, ['X-Spam-Status','X-Mailer']);

如果您的服务器不支持CONDSTORE和QRESYNC

如果您的服务器不支持CONDSTORE和QRESYNC,那么您必须定期或始终获取邮箱中所有消息的标志和UID(从时间到时间或始终)以跟踪标志更改和已删除的消息。为了将流量保持在尽可能低的水平,您应该运行两个查询,一个用于新消息,您将获取所需的所有标题,另一个查询您将仅请求旧消息的uid、message-id和标志。使用您存储的上次获取的uid值来区分新旧消息(前提是uidvalidity没有更改)。

// retrieve only flags, uid and message-id of messages (to update their status).
// All messages with a uid lower than $lastfetcheduid that are known to your application but aren't in the result set of this function have been deleted from the mailbox

$messagearray = $mailbox->getMessageupdate($lastfetcheduid);

foreach ($messagearray as $message) {
  // $message is an object of \bjc\roundcubeimap\message
}

请注意,$message对象及其子对象$messageheaders将不具有标准标题集。默认情况下,仅提供$uid、$id和标志。如果您还需要更多标题,您可以通过在函数调用中提供第二个参数来添加它们。

$messagearray = $mailbox->getMessageupdate($lastfetcheduid, false, ['subject', 'date']);

更新查询后,运行新消息的查询

$messagearray = $mailbox->getMessageshigherthan($lastfetcheduid);

foreach ($messagearray as $message) {
  // $message is an object of \bjc\roundcubeimap\message
}

消息标题

要从消息对象检索标题,您有以下选项

// message identification
$uid = $message->getUID(); // UID of message
$id = $message->getID(); // globally unique alphanumeric message ID

// Date and subject
$date = $message->getDate); // A datetime object
$timestamp = $message->getTimestamp(); // The timestamp of the date
$subject = $message->getSubject(); // string

// Addresses
$from = $message->getFrom(); // $from is an object of \bjc\roundcubeimap\emailaddress
$to = $message->getTo(); // $to is an array of objects of \bjc\roundcubeimap\emailaddress
$cc = $message->getCC(); // $cc is an array of objects of \bjc\roundcubeimap\emailaddress

// Flags
$isAnswered = $message->isAnswered; // true if ANSWERED flag is set, otherwise false
$isDeleted = $message->isDeleted; // true if DELETED flag is set, otherwise false
$isDraft = $message->isDraft; // true if DRAFT flag is set, otherwise false
$isSeen = $message->isAnswered; // true if SEEN flag is set, otherwise false
$isFlagged = $message->isFlagged; // true if FLAGGED flag is set, otherwise false

// get a specific header
$value = $message->getheader($headername);

// get all headers
$headerarray = $message->getHeaders();

电子邮件地址对象

对于电子邮件地址对象,您可以执行以下操作

// example: Guybrush Threepwood <guy@mightypirates.com>
$address = $from->getAddress(); // guy@mightypirates.com
$mailbox = $from->getMailbox(); // guy
$hostname = $from->getHostname(); // mightypirates.com
$name = $from->getName(); // Guybrush Threepwood

$fulladdress = $from->getFulladdress; // Guybrush Threepwood <guy@mightypirates.com>

消息部分

// get plain text of email if present
$plaintext = $message->getBodyText();

// get html text of message if present
$htmltext = $message->getBodyHtml();

// get attachments of message
$attachments = $message->getAttachments(); // $attachment is an array of objects of class \bjc\roundcubeimap\attachment

// get inline images of message
$inlineimages = $message->getInlineobjects(); // $inlineimages is an array of objects of class \bjx\roundcubeimap\attachment

附件和内联对象

foreach ($attachments as $attachment) {

   $filename = $attachment->getFilename();
   $charset = $attachment->getCharset(); // if available
   $mime_id = $attachment->getMimeId(); // get mime_id (also called part number) to retrieve the data of the attachment later
   $data = $attachment->getData(); // content of attachment

}

无论是否需要,获取(并存储)应用程序中所有的附件都是昂贵的。因此,您可能希望在应用程序中保存$filename和$mime_id,只有在用户请求附件的数据时才从IMAP服务器获取数据。您可以从消息对象中后来获取具有$mime_id(也称为部分号)的附件。

$attachment = $message->getAttachment($mime_id); // returns the attachment object
$data = $attachment->getData();

内联图像使用相同的类(\bjc\roundcubeimap\attachment),因此具有相同的方法。

foreach ($inlineobjects as $inlineobject) {

   $filename = $inlineobject->getFilename();
   $charset = $inlineobject->getCharset(); // if available
   $data = $inlineobject->getData(); // content of inline image

}

检索完整的Mime消息

有时您需要获取完整的Mime消息以进一步处理。

$mimemessage = $message->getMimemessage();

标记消息

您可以在邮箱对象或消息对象中设置和清除消息标记。

// First parameter is an array of the flags you want to set, second parameter is the message set you want to set the flags for
// returns true if successful, throws exception if not

$message_set = '1:*';
$flags = array('FLAGGED', 'SEEN');

$result = $mailbox->setFlag($flags, $message_set);

// First parameter is an array of the flags you want to clear, second parameter is the message set you want to clear the flags for
// returns true if successful, throws exception if not
$message_set = '12322';
$flags = array('FLAGGED');

$result = $mailbox->clearFlag($flags, $message_set);


// Call from within the message object
$result = $message->setFlag($flags);
$result = $message->clearFlag($flags);

复制、移动(在账户内)、删除消息

您可以在邮箱对象或消息对象中复制、移动和删除消息。

$message_set = '1:10';
$targetmailbox = 'newmailboxname';

// returns true if successful, throws exception if not
$result = $mailbox->copyMessages($message_set, $targetmailbox);
$result = $mailbox->moveMessages($message_set, $targetmailbox);

$message_set = array(11320,11330);
$result = $mailbox->deleteMessages($message_set);

// Call from within the message object
// returns true if successful, throws exception if not
$result = $message->copyMessage($targetmailbox);
$result = $message->moveMessage($targetmailbox);
$result = $message->deleteMessage();

计算消息数量

您可以在邮箱对象中计算所有消息、最近的消息或未读消息的数量。

// returns number of messages if successful, throws exception if not
$number_of_messages = $mailbox->countMessage();
$number_of_recent_messages = $mailbox->countRecent();
$number_of_unseen_messages = $mailbox->countUnseen();

将消息附加到邮箱

如果您已经发送了一条消息,可能希望将发送的消息保存到一个文件夹中。本包仅用于管理IMAP邮箱,而不是用于与SMTP服务器通信以发送消息。

所以,假设您已经使用其他库发送了一封电子邮件,例如PHPMailer。

$mail = new \PHPMailer();
// set all your mail credentials here

// Now send message
$mail->send();

// Get mime mailstring from PHPMailer
$mailstring = $mail->getSentMIMEMessage();

// Save it to an existing mailbox object

$flags = array('SEEN');

$uid_of_appended_message = $mailbox->appendMessage($mailstring, $flags);

将消息移动到其他账户

如果您想将消息从一个账户移动到另一个账户,可以使用fetchMimemessage方法检索消息,并使用appendMessage方法一起。

// Get connection to source account and access the mailbox and message
$server = new \bjc\roundcubeimap\server('hostname_account1');
$connection = $server->authenticate('username_account1', 'password_account1');
$mailbox = $connection->getMailbox('mailboxname_account1');
$message = $mailbox->getMessage($uid);

// fetch mime message from server
$mimemessage = $message->getMimemessage();

// Get connection to destination account and access the mailbox
$server = new \bjc\roundcubeimap\server('hostname_account1');
$connection = $server->authenticate('username_account1', 'password_account2');
$mailbox = $connection->getMailbox('mailboxname_account2');

// Append the mime message to the mailbox
$mailbox->appendMessage($mimemessage);

待办事项

  • 创建类\bjc\roundcubeimap\embeddedmessage,以提供处理嵌入式消息的可能性。