popphp/pop-mail

Pop PHP 框架的邮件组件

4.0.2 2024-05-17 18:07 UTC

README

Build Status Coverage Status

Join the chat at https://popphp.slack.com Join the chat at https://discord.gg/TZjgT74U7E

概述

pop-mail 是 Pop PHP 框架的主要邮件组件。它提供了一套强大的功能,用于管理通过互联网发送和接收邮件的各个方面。它提供了以下功能:

  • 消息
    • 创建具有多种 MIME 类型和附件的邮件消息
    • 通过邮件发送器对象发送消息,或将邮件消息保存以供以后发送
    • 通过队列发送消息给多个接收者
  • 邮件传输方式
    • 管理从服务器到服务器的应用程序连接中发送邮件消息*
    • 向接收者队列发送电子邮件,并进行个别消息定制
    • 可用的邮件传输方式可以互换
      • Mailgun 传输方式:利用 Mailgun API
      • Sendgrid 传输方式:利用 Sendgrid API
      • Office 365 传输方式:利用 Office 365 邮件 API
      • AWS SES 传输方式:利用 AWS SDK
      • Google 传输方式:利用 Gmail API
      • SMTP 传输方式:利用标准 SMTP 连接
      • Sendmail 传输方式:利用基本 Sendmail 连接
  • 邮件客户端
    • 通过服务器到服务器的应用程序连接管理邮箱、消息、数据、附件和状态*
      • Office 365 客户端:利用 Office 365 邮件 API
      • Google 客户端:利用 Gmail API
      • IMAP/POP3 客户端:利用标准 IMAP 或 POP3 连接 (出于安全原因,IMAP & POP3 的支持越来越广泛,并在一些流行的企业邮件平台中已弃用)

* - 注意: 此组件的主要用途是作为服务器到服务器的应用程序连接。这意味着组件将用于具有适当访问权限和权限的应用程序,该应用程序可以代表由应用程序管理的用户或用户的电子邮件执行操作。此组件并不针对个人用户邮件应用程序使用案例。请参考您尝试使用此组件连接应用程序的任何邮件平台的在线文档、指南和政策。请小心授予应用程序实例的访问权限和分配权限。始终遵循您选择的邮件平台推荐的安全策略和指南。

pop-mailPop PHP 框架 的组件。

安装

使用 Composer 安装 pop-mail

composer require popphp/pop-mail

或者,在 composer.json 文件中要求它

"require": {
    "popphp/pop-mail" : "^4.0.0"
}

顶部

快速入门

示例 1: 通过 Mailgun API 发送消息

use Pop\Mail\Message;
use Pop\Mail\Mailer;
use Pop\Mail\Transport\Mailgun;

// Create the transport and mailer objects
$transport = new Mailgun([
    'api_url' => 'MAILGUN_API_URL',
    'api_key' => 'MAILGUN_API_KEY',
]);
$mailer = new Mailer($transport);

// Create the message object
$message = new Message('My Message Subject');
$message->setTo('you@domain.com');
$message->setFrom('me@domain.com');
$message->setBody('Hello World! This is a text body!');

// Send the message
$mailer->send($message);

示例 2: 通过 SMTP 连接发送消息

use Pop\Mail\Message;
use Pop\Mail\Mailer;
use Pop\Mail\Transport\Smtp;

$smtpOptions = [
    'host'       => 'SMTP_HOST_DOMAIN',
    'port'       => 'SMTP_PORT',
    'username'   => 'SMTP_USERNAME',
    'password'   => 'SMTP_PASSWORD',
    'encryption' => 'SMTP_ENCRYPTION'
];

// Create the transport and mailer objects
$transport = new Smtp($smtpOptions);
$mailer    = new Mailer($transport);

// Create the message object
$message   = new Message('My Message Subject');
$message->setTo('you@domain.com');
$message->setFrom('me@domain.com');
$message->setBody('Hello World! This is a text body!');

// Send the message
$mailer->send($message);

顶部

消息

可以创建消息对象并将其传递给邮件发送器对象,由应用程序发送。

创建一个简单的纯文本邮件消息

use Pop\Mail\Message;

$message = new Message('My Message Subject');
$message->setTo('you@domain.com');
$message->setFrom('me@domain.com');
$message->setBody('Hello World! This is a text body!');

创建包含文本和 HTML 部分的邮件消息

use Pop\Mail\Message;

$message = new Message('My Message Subject');
$message->setTo('you@domain.com');
$message->setFrom('me@domain.com');
$message->addText('Hello World! This is a text body!');
$message->addHtml('<html><body><h1>Hello World!</h1><p>This is an HTML body!</p></body></html>');

创建带有文件附件的邮件消息

use Pop\Mail\Message;

$message = new Message('My Message Subject');
$message->setTo('you@domain.com');
$message->setFrom('me@domain.com');
$message->setBody('Hello World! This is a text body!');
$message->attachFile(__DIR__ . '/image.jpg');

从文件内容流创建带有文件附件的邮件消息

use Pop\Mail\Message;

$message = new Message('My Message Subject');
$message->setTo('you@domain.com');
$message->setFrom('me@domain.com');
$message->setBody('Hello World! This is a text body!');
$message->attachFileFromStream($fileContents, 'filename.pdf');

顶部

邮件发送器

创建消息对象后,可以将其传递给邮件发送对象进行发送。邮件发送对象需要传输对象来执行发送消息所需的任务,并通过提供的邮件平台发送消息。

use Pop\Mail\Message;
use Pop\Mail\Mailer;
use Pop\Mail\Transport\Sendmail;

$transport = new Sendmail();
$mailer    = new Mailer($transport);
$message   = new Message('My Message Subject');
$message->setTo('you@domain.com');
$message->setFrom('me@domain.com');
$message->setBody('Hello World! This is a text body!');

$mailer->send($message);

顶部

传输方式

所有可用的传输都共享相同的接口,可以互换使用。但是,它们各自需要不同的配置,以符合它们各自邮件平台的规范。

Mailgun

Mailgun传输需要api_urlapi_key。API密钥可以从Mailgun管理门户获取。Mailgun API URL通常是包含您批准的邮件域的字符串,例如

https://api.mailgun.net/v3/YOUR_MAIL_DOMAIN/messages
use Pop\Mail\Mailer;
use Pop\Mail\Transport\Mailgun;

$mailgunOptions = [
    'api_url' => 'MAILGUN_API_URL',
    'api_key' => 'MAILGUN_API_KEY',
];
$transport = new Mailgun($mailgunOptions);
$mailer    = new Mailer($transport);

顶部

Sendgrid

Sendgrid传输需要api_urlapi_key。这些值可以从Sendgrid管理门户获取。

use Pop\Mail\Mailer;
use Pop\Mail\Transport\Sendgrid;

$sendgridOptions = [
    'api_url' => 'SENDGRID_API_URL',
    'api_key' => 'SENDGRID_API_KEY',
];
$transport = new Sendgrid($sendgridOptions);
$mailer    = new Mailer($transport);

顶部

Office 365

Office 365传输需要更多一些配置选项,这些选项可以从Office 365管理门户中获取批准的应用程序。您需要以下信息

  • 客户端ID
  • 客户端密钥
  • 作用域(这通常类似于https://graph.microsoft.com/.default
  • 租户ID
  • 账户ID(这通常是正在使用的用户邮箱的object_id

您可以创建一个Office 365传输对象,然后请求并存储未来请求所需的令牌

use Pop\Mail\Mailer;
use Pop\Mail\Transport\Office365;

$transport = new Office365();
$transport->createClient([
    'client_id'     => 'O365_CLIENT_ID',
    'client_secret' => 'O365_CLIENT_SECRET',
    'scope'         => 'O365_SCOPE',
    'tenant_id'     => 'O365_TENANT_ID',
    'account_id'    => 'O365_ACCOUNT_ID',
]);

// Fetch the token and its expiration to be stored with your application for future use
$transport->requestToken();
$accessToken  = $transport->getToken();
$tokenExpires = $transport->getTokenExpires();

$mailer = new Mailer($transport);

在稍后调用Office 365传输对象时,您可以重用令牌(如果它尚未过期)

use Pop\Mail\Mailer;
use Pop\Mail\Transport\Office365;

$transport = new Office365();
$transport->createClient([
    'client_id'     => 'O365_CLIENT_ID',
    'client_secret' => 'O365_CLIENT_SECRET',
    'scope'         => 'O365_SCOPE',
    'tenant_id'     => 'O365_TENANT_ID',
    'account_id'    => 'O365_ACCOUNT_ID',
]);

// Get the access token and its expiration from your application store
$transport->setToken($accessToken)
$transport->setTokenExpires($tokenExpires);

$mailer = new Mailer($transport);

如果令牌已过期,传输对象将自动刷新它。在此点,您可以从传输对象中获取新令牌及其过期时间,并将它们存储起来。

顶部

AWS SES

AWS SES传输需要从AWS SES管理控制台中获取的keysecret

use Pop\Mail\Mailer;
use Pop\Mail\Transport\Ses;

$sesOptions = [
    'key'    => 'AWS_SES_KEY',
    'secret' => 'AWS_SES_SECRET',
];
$transport = new Ses($sesOptions);
$mailer    = new Mailer($transport);

顶部

Google

Google传输需要在Google管理门户和云控制台中执行多个配置步骤。这包括将批准的应用程序设置为服务帐户及其必要要求。完成后,您应该会提示下载包含您应用程序适当凭据和数据的JSON文件

{
  "type": "service_account",
  "project_id": "PROJECT_ID",
  "private_key_id": "PRIVATE_KEY_ID",
  "private_key": "PRIVATE_KEY",
  "client_email": "CLIENT_EMAIL",
  "client_id": "CLIENT_ID",
  "auth_uri": "AUTH_URI",
  "token_uri": "TOKEN_URI",
  "auth_provider_x509_cert_url": "AUTH_PROVIDER",
  "client_x509_cert_url": "CLIENT_CERT_URL",
  "universe_domain": "UNIVERSE_DOMAIN"
}

您可以直接将JSON文件传递给Google传输对象,以及正在使用的用户电子邮件。从那里,您可以请求并存储未来请求所需的令牌

use Pop\Mail\Mailer;
use Pop\Mail\Transport\Google;

$transport = new Google();
$transport->createClient('my-google-app-config.json', 'me@domain.com');

// Fetch the token and its expiration to be stored with your application for future use
$transport->requestToken();
$accessToken  = $transport->getToken();
$tokenExpires = $transport->getTokenExpires();

$mailer = new Mailer($transport);

在稍后调用Google传输对象时,您可以重用令牌(如果它尚未过期)

use Pop\Mail\Mailer;
use Pop\Mail\Transport\Google;

$transport = new Google();
$transport->createClient('my-google-app-config.json', 'me@domain.com');

// Get the access token and its expiration from your application store
$transport->setToken($accessToken)
$transport->setTokenExpires($tokenExpires);

$mailer = new Mailer($transport);

如果令牌已过期,传输对象将自动刷新它。在此点,您可以从传输对象中获取新令牌及其过期时间,并将它们存储起来。

顶部

SMTP

SMTP传输需要典型的SMTP连接的标准配置参数

use Pop\Mail\Mailer;
use Pop\Mail\Transport\Smtp;

$smtpOptions = [
    'host'       => 'SMTP_HOST_DOMAIN',
    'port'       => 'SMTP_PORT',
    'username'   => 'SMTP_USERNAME',
    'password'   => 'SMTP_PASSWORD',
    'encryption' => 'SMTP_ENCRYPTION'
];

$transport = new Smtp($smtpOptions);
$mailer    = new Mailer($transport);

Sendmail

Sendmail是最基本的传输。它不太常用,不建议使用,但在测试和开发环境中可以使用。它利用服务器上运行的sendmail应用程序,因此需要在服务器和PHP中正确设置和配置它以与PHP的mail函数一起使用。如果需要,您可以将字符串$params传递给构造函数,该字符串将传递给mail函数调用。

use Pop\Mail\Mailer;
use Pop\Mail\Transport\Sendmail;

$transport = new Sendmail();
$mailer    = new Mailer($transport);

顶部

客户端

可用的邮件客户端可以用于在应用程序中监控邮箱及其消息内容。

Office 365 客户端

与Office 365传输类似,Office 365客户端需要更多一些配置选项,这些选项可以从Office 365管理门户中获取批准的应用程序。您需要以下信息

  • 客户端ID
  • 客户端密钥
  • 作用域(这通常类似于https://graph.microsoft.com/.default
  • 租户ID
  • 账户ID(这通常是正在使用的用户邮箱的object_id

您可以创建一个Office 365客户端对象,然后请求并存储未来请求所需的令牌

use Pop\Mail\Client\Office365;

$office365 = new Office365();
$office365->createClient([
    'client_id'     => 'O365_CLIENT_ID',
    'client_secret' => 'O365_CLIENT_SECRET',
    'scope'         => 'O365_SCOPE',
    'tenant_id'     => 'O365_TENANT_ID',
    'account_id'    => 'O365_ACCOUNT_ID',
]);

// Fetch the token and its expiration to be stored with your application for future use
$office365->requestToken();
$accessToken  = $office365->getToken();
$tokenExpires = $office365->getTokenExpires();

在稍后调用Office 365客户端对象时,您可以重用令牌(如果它尚未过期)

use Pop\Mail\Client\Office365;

$office365 = new Office365();
$office365->createClient([
    'client_id'     => 'O365_CLIENT_ID',
    'client_secret' => 'O365_CLIENT_SECRET',
    'scope'         => 'O365_SCOPE',
    'tenant_id'     => 'O365_TENANT_ID',
    'account_id'    => 'O365_ACCOUNT_ID',
]);

// Get the access token and its expiration from your application store
$office365->setToken($accessToken)
$office365->setTokenExpires($tokenExpires);

如果令牌已过期,客户端对象将自动刷新它。此时,您可以从客户端对象获取新令牌及其过期时间并存储它们。

从那里,您可以与客户端交互以获取消息及其内容。

获取消息
// Defaults to the Inbox and a limit of 10 messages. Returns an array of messages
$messages = $office365->getMessages();

仅搜索未读消息,限制为5条

$messages = $office365->getMessages('Inbox', ['unread' => true], 5);
获取一条消息

当消息返回时,它们将带有任何与之关联的ID。使用该ID获取单个消息

// Returns an array of message data
$message = $office365->getMessage($messageId);

您还可以获取原始消息

// Returns a string of the full message content
$message = $office365->getMessage($messageId, true);
获取消息的附件
// Returns an array of attachments
$attachments = $office365->getAttachments($messageId);
获取一个附件

当消息的附件返回时,它们将带有任何与之关联的ID。使用该ID获取单个消息附件

// Returns an array of attachment data, including the attachment data contents
$attachment = $office365->getAttachment($messageId, $attachmentId);

顶部

Google 客户端

类似于Google传输,Google客户端需要在Google管理门户和云控制台中执行一系列配置步骤。这包括将批准的应用程序设置为服务帐户及其必要的要求。完成后,您将提示下载包含应用程序适当凭证和数据的JSON文件

{
  "type": "service_account",
  "project_id": "PROJECT_ID",
  "private_key_id": "PRIVATE_KEY_ID",
  "private_key": "PRIVATE_KEY",
  "client_email": "CLIENT_EMAIL",
  "client_id": "CLIENT_ID",
  "auth_uri": "AUTH_URI",
  "token_uri": "TOKEN_URI",
  "auth_provider_x509_cert_url": "AUTH_PROVIDER",
  "client_x509_cert_url": "CLIENT_CERT_URL",
  "universe_domain": "UNIVERSE_DOMAIN"
}

您可以直接将JSON文件传递给Google客户端对象,同时提供正在使用的用户电子邮件。从那里,您可以请求并存储未来请求所需的令牌

use Pop\Mail\Client\Google;

$google = new Google();
$google->createClient('my-google-app-config.json', 'me@domain.com');

// Fetch the token and its expiration to be stored with your application for future use
$google->requestToken();
$accessToken  = $google->getToken();
$tokenExpires = $google->getTokenExpires();

在稍后调用Google客户端对象时,您可以重用令牌(如果它尚未过期)

use Pop\Mail\Client\Google;

$google = new Google();
$google->createClient('my-google-app-config.json', 'me@domain.com');

// Get the access token and its expiration from your application store
$google->setToken($accessToken)
$google->setTokenExpires($tokenExpires);

如果令牌已过期,客户端对象将自动刷新它。此时,您可以从客户端对象获取新令牌及其过期时间并存储它们。

从那里,您可以与客户端交互以获取消息及其内容。

获取消息
// Defaults to the Inbox and a limit of 10 messages. Returns an array of messages
$messages = $google->getMessages();

仅搜索未读消息,限制为5条

$messages = $google->getMessages('Inbox', ['unread' => true], 5);
获取一条消息

当消息返回时,它们将带有任何与之关联的ID。使用该ID获取单个消息

// Returns an array of message data
$message = $google->getMessage($messageId);

您还可以获取原始消息

// Returns a string of the full message content
$message = $google->getMessage($messageId, true);
获取消息的附件
// Returns an array of attachments
$attachments = $google->getAttachments($messageId);
获取一个附件

当消息的附件返回时,它们将带有任何与之关联的ID。使用该ID获取单个消息附件

// Returns the attachment data contents
$attachment = $google->getAttachment($messageId, $attachmentId);

顶部

IMAP/POP3

IMAP & POP3客户端可用,但支持度正在降低。在某些流行的企业邮件平台上,它们的用法已被弃用。请谨慎使用。

use Pop\Mail\Client\Imap;

$imap = new Client\Imap('imap.gmail.com', 993);
$imap->setUsername('me@domain.com')
     ->setPassword('password');

$imap->setFolder('INBOX');
$imap->open('/ssl');

// Sorted by date, reverse order (newest first)
$ids     = $imap->getMessageIdsBy(SORTDATE, true);
$headers = $imap->getMessageHeadersById($ids[0]);
$parts   = $imap->getMessageParts($ids[0]);

// Assuming the first part is an image attachment, display image
header('Content-Type: image/jpeg');
header('Content-Length: ' . strlen($parts[0]->content));
echo $parts[0]->content;

顶部

邮件队列

您可以创建邮件队列以同时管理并向多个收件人发送消息。好处是消息体可以包含占位符,可以替换为单个用户数据以实现定制和更好的用户体验。

use Pop\Mail\Message;
use Pop\Mail\Queue;
use Pop\Mail\Mailer;
use Pop\Mail\Transport\Sendmail;

$queue = new Queue();
$queue->addRecipient([
    'email'   => 'me@domain.com',
    'name'    => 'My Name',
    'company' => 'My Company',
    'url'     => 'http://www.domain1.com/'
]);
$queue->addRecipient([
    'email'   => 'another@domain.com',
    'name'    => 'Another Name',
    'company' => 'Another Company',
    'url'     => 'http://www.domain2.com/'
]);

$messageBody = <<<TEXT
How are you doing? Your [{company}] is great!
I checked it out at [{url}]
TEXT;

$message = new Message('Hello [{name}]!');
$message->setFrom('noreply@domain.com');
$message->setBody($messageBody);

$queue->addMessage($message);

$mailer = new Mailer(new Sendmail());
$mailer->sendFromQueue($queue);

顶部

保存邮件

通过将邮件消息保存到应用程序中的存储位置,您可以在稍后日期和时间调用它们,并从该位置发送。

use Pop\Mail\Message;
use Pop\Mail\Mailer;
use Pop\Mail\Transport\Sendmail;

$message1 = new Mail\Message('Hello World');
$message1->setTo('user1@domain.com');
$message1->setFrom('me@domain.com');
$message1->addText('Hello World! This is a test!');
$message1->addHtml('<html><body><h1>Hello World!</h1><p>This is a test!</p></body></html>');
$message1->save(__DIR__ . '/mail-queue/message1.msg'); 

$message2 = new Mail\Message('Hello World');
$message2->setTo('user2@domain.com');
$message2->setFrom('me@domain.com');
$message2->addText('Hello World! This is a test!');
$message2->addHtml('<html><body><h1>Hello World!</h1><p>This is a test!</p></body></html>');
$message2->save(__DIR__ . '/mail-queue/message2.msg'); 

$mailer = new Mailer(new Sendmail());
$mailer->sendFromDir(__DIR__ . '/mail-queue');

顶部