标签归档:mail

Zend Framework 2.x 之 Zend\Mail

Introduction to Zend\Mail

Getting started
Zend\Mail provides generalized普遍 functionality to compose组成 and send both text and MIME-compliant multipart email messages. Mail can be sent with Zend\Mail via the Mail\Transport\Sendmail, Mail\Transport\Smtp or the Mail\Transport\File transport. Of course, you can also implement your own transport by implementing the Mail\Transport\TransportInterface.(邮件传送出去使用Sendmail或Smtp很容易理解,但是File就有点困惑)

Simple email with Zend\Mail
A simple email consists of one or more recipients(一个或多个接收人), a subject, a body and a sender. To send such a mail using Zend\Mail\Transport\Sendmail, do the following:

use Zend\Mail;

$mail = new Mail\Message();
$mail->setBody('This is the text of the email.');
$mail->setFrom('Freeaqingme@example.org', 'Sender\'s name');
$mail->addTo('Matthew@example.com', 'Name of recipient');
$mail->setSubject('TestSubject');

$transport = new Mail\Transport\Sendmail();
$transport->send($mail);

总体上,就是构建一个消息,然后使用一个Transport发送出去。

Note
Minimum definitions
In order to send an email using Zend\Mail you have to specify at least one recipient as well as a message body. Please note that each Transport may require additional parameters to be set.

For most mail attributes there are “get” methods to read the information stored in the message object. for further details, please refer to the API documentation.

You also can use most methods of the Mail\Message object with a convenient fluent interface.(说可以链式构建消息)

use Zend\Mail;

$mail = new Mail\Message();
$mail->setBody('This is the text of the mail.')
     ->setFrom('somebody@example.com', 'Some Sender')
     ->addTo('somebody_else@example.com', 'Some Recipient')
     ->setSubject('TestSubject');

Configuring the default sendmail transport

The most simple to use transport is the Mail\Transport\Sendmail transport class. It is essentially a wrapper to the PHP mail() function. If you wish to pass additional parameters to the mail() function, simply create a new transport instance and pass your parameters to the constructor.

Passing additional parameters
This example shows how to change the Return-Path of the mail() function.

use Zend\Mail;

$mail = new Mail\Message();
$mail->setBody('This is the text of the email.');
$mail->setFrom('Freeaqingme@example.org', 'Dolf');
$mail->addTo('matthew@example.com', 'Matthew');
$mail->setSubject('TestSubject');

$transport = new Mail\Transport\Sendmail('-freturn_to_me@example.com');
$transport->send($mail);

Note
Safe mode restrictions
Supplying additional parameters to the transport will cause the mail() function to fail if PHP is running in safe mode.(启动安全模式可能使得发邮件失败)

Note
Choosing your transport wisely聪明地
Although the sendmail transport is the transport that requires only minimal configuration, it may not be suitable for your production environment. This is because emails sent using the sendmail transport will be more often delivered to SPAM-boxes. This can partly be remedied by using the SMTP Transport combined with an SMTP server that has an overall good reputation. Additionally, techniques such as SPF and DKIM may be employed to ensure even more email messages are delivered as should.(使用Sendmail发送多层垃圾,使用SMTP)

Zend\Mail\Message

Overview
The Message class encapsulates a single email message as described in RFCs 822 and 2822. It acts basically as a value object for setting mail headers and content.

If desired, multi-part email messages may also be created. This is as trivial平常的 as creating the message body using the Zend\Mime component, assigning it to the mail message body.

The Message class is simply a value object. It is not capable能胜任的 of sending or storing itself; for those purposes, you will need to use, respectively, a Transport adapter or Storage adapter.

Quick Start
Creating a Message is simple: simply instantiate例示 it.

use Zend\Mail\Message;

$message = new Message();

Once you have your Message instance, you can start adding content or headers. Let’s set who the mail is from, who it’s addressed to, a subject, and some content:

$message->addFrom("matthew@zend.com", "Matthew Weier O'Phinney")
        ->addTo("foobar@example.com")
        ->setSubject("Sending an email from Zend\Mail!");
$message->setBody("This is the message body.");

You can also add recipients to carbon-copy (“Cc:”) or blind carbon-copy (“Bcc:”). 抄送 和 密送

$message->addCc("ralph.schindler@zend.com")
        ->addBcc("enrico.z@zend.com");

If you want to specify an alternate address to which replies may be sent, that can be done, too.

$message->addReplyTo("matthew@weierophinney.net", "Matthew");

Interestingly, RFC822 allows for multiple “From:” addresses. When you do this, the first one will be used as the sender, unless you specify a “Sender:” header. The Message class allows for this.

/*
 * Mail headers created:
 * From: Ralph Schindler <ralph.schindler@zend.com>, Enrico Zimuel <enrico.z@zend.com>
 * Sender: Matthew Weier O'Phinney <matthew@zend.com></matthew>
 */
$message->addFrom("ralph.schindler@zend.com", "Ralph Schindler")
        ->addFrom("enrico.z@zend.com", "Enrico Zimuel")
        ->setSender("matthew@zend.com", "Matthew Weier O'Phinney");

可以有多个from,默认第一个为sender,可用setSender明确设置sender。

By default, the Message class assumes ASCII encoding for your email. If you wish to use another encoding, you can do so; setting this will ensure all headers and body content are properly encoded using quoted-printable encoding. 默认ASCII编码

$message->setEncoding("UTF-8");

If you wish to set other headers, you can do that as well. 添加邮件头信息

/*
 * Mail headers created:
 * X-API-Key: FOO-BAR-BAZ-BAT
 */
$message->getHeaders()->addHeaderLine('X-API-Key', 'FOO-BAR-BAZ-BAT');

Sometimes you may want to provide HTML content, or multi-part content. To do that, you’ll first create a MIME message object, and then set it as the body of your mail message object. When you do so, the Message class will automatically set a “MIME-Version” header, as well as an appropriate “Content-Type” header.

In addition you can check how to add attachment to your message E-mail Attachments.

use Zend\Mail\Message;
use Zend\Mime\Message as MimeMessage;
use Zend\Mime\Part as MimePart;

$text = new MimePart($textContent);
$text->type = "text/plain";

$html = new MimePart($htmlMarkup);
$html->type = "text/html";

$image = new MimePart(fopen($pathToImage, 'r'));
$image->type = "image/jpeg";

$body = new MimeMessage();
$body->setParts(array($text, $html, $image));

$message = new Message();
$message->setBody($body);

If you want a string representation of your email, you can get that:

echo $message->toString();

Finally, you can fully introspect内现 the message – including getting all addresses of recipients and senders, all headers, and the message body.

// Headers
// Note: this will also grab all headers for which accessors/mutators exist in
// the Message object itself.
foreach ($message->getHeaders() as $header) {
    echo $header->toString();
    // or grab values: $header->getFieldName(), $header->getFieldValue()
}

// The logic below also works for the methods cc(), bcc(), to(), and replyTo()
foreach ($message->getFrom() as $address) {
    printf("%s: %s\n", $address->getEmail(), $address->getName());
}

// Sender
$address = $message->getSender();
if(!is_null($address)) {
   printf("%s: %s\n", $address->getEmail(), $address->getName());
}

// Subject
echo "Subject: ", $message->getSubject(), "\n";

// Encoding
echo "Encoding: ", $message->getEncoding(), "\n";

// Message body:
echo $message->getBody();     // raw body, or MIME object
echo $message->getBodyText(); // body as it will be sent

Once your message is shaped to your liking, pass it to a mail transport in order to send it!

$transport->send($message);

消息准备好,传递给Transport的send方法。

Zend\Mail\Transport
Overview
Transports take care of the actual delivery of mail. Typically, you only need to worry about two possibilities: using PHP’s native mail() functionality, which uses system resources to deliver mail, or using the SMTP protocol for delivering mail via a remote server. Zend Framework also includes a “File” transport, which creates a mail file for each message sent; these can later be introspected as logs or consumed for the purposes of sending via an alternate transport mechanism later.(提供了FileTransport,用来日志等)

The Zend\Mail\Transport interface defines exactly one method, send(). This method accepts a Zend\Mail\Message instance, which it then introspects and serializes in order to send. 只有一个send()方法

Quick Start
Using a mail transport is typically as simple as instantiating it, optionally configuring it, and then passing a message to it. 实例化 配置 传递一个消息给它

Sendmail Transport Usage
SMTP Transport Usage

use Zend\Mail\Message;
use Zend\Mail\Transport\Smtp as SmtpTransport;
use Zend\Mail\Transport\SmtpOptions;

$message = new Message();
$message->addTo('matthew@zend.com')
        ->addFrom('ralph.schindler@zend.com')
        ->setSubject('Greetings and Salutations!')
        ->setBody("Sorry, I'm going to be late today!");

// Setup SMTP transport using LOGIN authentication
$transport = new SmtpTransport();
$options   = new SmtpOptions(array(
    'name'              => 'localhost.localdomain',
    'host'              => '127.0.0.1',
    'connection_class'  => 'login',
    'connection_config' => array(
        'username' => 'user',
        'password' => 'pass',
    ),
));
$transport->setOptions($options);
$transport->send($message);

File Transport Usage

use Zend\Mail\Message;
use Zend\Mail\Transport\File as FileTransport;
use Zend\Mail\Transport\FileOptions;

$message = new Message();
$message->addTo('matthew@zend.com')
        ->addFrom('ralph.schindler@zend.com')
        ->setSubject('Greetings and Salutations!')
        ->setBody("Sorry, I'm going to be late today!");

// Setup File transport
$transport = new FileTransport();
$options   = new FileOptions(array(
    'path'              => 'data/mail/',
    'callback'  => function (FileTransport $transport) {
        return 'Message_' . microtime(true) . '_' . mt_rand() . '.txt';
    },
));
$transport->setOptions($options);
$transport->send($message);

InMemory Transport Usage

use Zend\Mail\Message;
use Zend\Mail\Transport\InMemory as InMemoryTransport;

$message = new Message();
$message->addTo('matthew@zend.com')
        ->addFrom('ralph.schindler@zend.com')
        ->setSubject('Greetings and Salutations!')
        ->setBody("Sorry, I'm going to be late today!");

// Setup InMemory transport
$transport = new InMemoryTransport();
$transport->send($message);

// Verify the message:
$received = $transport->getLastMessage();

The InMemory transport is primarily of interest when in development or when testing.(InMemoryTransport就是一个垃圾桶。)

Zend\Mail\Transport\SmtpOptions
Zend\Mail\Transport\FileOptions

Zend\Mail 使用范本 使用Mime发送附件(图片 Excel Zip等)

首先需要知道,Zend\Mime\Part抽象了文件(可以是文本文件 HTML文件 图片 Excel zip等),一个Message就是有一个或多个Part组成(一个或多个文件组成),这些文件之间的分隔需要使用Zend\Mime\Mime来进行,所以一个Message还有一个Mime对象。

每个Part,就是文件,根据不同类型,实际可以用的设置会不同,但是接口统一。比如有setType()用来设置Mime类型(就是标识文件的类型),setFilenme()设置文件名(需要带后缀名,可能会根据后缀名识别类型,QQ邮箱就是如此),setEncoding()设置编码(一般针对二进制文件,对二进制流进行编码后传输,所以一般是针对图片 Zip包这些文件,对应文本文件就没有实际作用),setChartset()设置文件编码(这个主要针对文本文件,涉及其中的字符编码,对二进制文件无效),setDisposition()设置是内联还是附件形式(用于邮件)。

另外,Part的getContent()可以获取使用设置的编码编码之后的输出,比如要还原一张图片,反向解码就是二进制流。setType()常见有”text/plain”,”text/html”, “text/xml”, “text/css”, “image/jpeg”, “application/json”, “text/javascript”。对应于HTTP响应,这些值将填充头Content-Type,客户端根据这个值来识别文件类型(决定如何处理)。

<?php
use Yaf\Controller_Abstract as ControllerAbstract;
use Zend\Db\Adapter\Adapter;
use Thousand\Tongtool\Session as TongtoolSession;
use Thousand\Services;
use Zend\Mail;
use Zend\Mail\Message;
use Zend\Mail\Transport\File as FileTransport;
use Zend\Mail\Transport\FileOptions;
use Zend\Mail\Transport\Smtp as SmtpTransport;
use Zend\Mail\Transport\SmtpOptions;
use Zend\Mail\Transport\InMemory as InMemoryTransport;
use Zend\Mime\Message as MimeMessage;
use Zend\Mime\Part as MimePart;

class TestController extends ControllerAbstract
{

    public function helloAction()
    {
        $adapter = Services::get('adapter');
         
        $jobs = $adapter->query("SELECT * FROM job", Adapter::QUERY_MODE_EXECUTE);
         
        print_r($jobs->toArray());
    }
    
    public function sendAction()
    {
        $text = new MimePart('Hello World');
        $text->type = "text/plain";
        
        // 邮件主体,覆盖了纯文本设置
        $html = new MimePart('<span style="color:red">Hi, Vfeelit...<a href="http://blog.ifeeline.com">this is my blog</a');
        $html->type = "text/html";

        // 作为附件 但是被QQ邮箱识别为bin文件
        $image = new MimePart(file_get_contents("D:/mailtest.jpg"));
        $image->type = "image/jpeg";
        
        // 设置MimeMessage
        $body = new MimeMessage();
        $body->setParts(array($text, $html, $image));
        
        
        // 1 设置信息
        $message = new Message();
        $message->addTo('jinsheng.sha@1000shores.com')
                ->addFrom('vfeelit@qq.com')
                ->setSubject('I want you.')
                //->setBody("I want you.");
                ->setBody($body);
        
        /*
                        完整参考
        $message->setTo('xxx')
                ->addTo('ifeeline@qq.com')      // 可以To多个人
                ->setFrom('xxx')
                ->addFrom('vfeelit@qq.com')     // 可以设置多个From
                ->setSender()                   // No addSender,默认是第一个From
                ->setCc()
                ->addCc()                       // 抄送
                ->setBcc()  
                ->addBcc()                      // 密送
                ->setReplyTo()                  // 回复给哪些人,应该是To对应,也可以多加
                ->addReplyTo()                  // 可以回复多个人
                ->setHeaders()                  // No addHeader(s)
                ->setSubject('I want you.')     // No addSubject
                ->setBody("I want you.");       // No addBody
        
        $message->getXxx()                      // 一系列的get方法
        
        $message->setEncoding("UTF-8")          // 默认为ACSSII
                ->fromString()                  // 用原始字符串构建
                ->toString()                    // 消息转换成字符串
                ->isValid()                     // 验证消息,返回布尔值
                
        // 邮件头设置
        $message->getHeaders()->addHeaderLine('X-API-Key', 'FOO-BAR-BAZ-BAT');
        $message->setHeaders() 需要传递一个Zend\Mail\Headers对象,每个单元是一个Zend\Mail\Header
        
        // 关于setBody,如果要发送HTML或者图片,就需要构建一个Zend\Mime\Message,一个Zend\Mime\Message由多个
        // Zend\Mime\Part组成,一个Zend\Mime\Part可以是一段纯文本,一个HTML片段,一张图片
        // 然后调用Zend\Mime\Message的setParts(array()),最后把这个Zend\Mime\Message传递给邮件消息的setBody
        $text = new MimePart($textContent);
        $text->type = "text/plain";
        
        $html = new MimePart($htmlMarkup);
        $html->type = "text/html";
        
        // 如果要成功发送一个图片附件,就必须设置如下几个参数,其中编码保守改为base64,默认是8bit
        // 经测试有些服务商无法读取这个内容
        $image = new MimePart(fopen($pathToImage, 'r'));
        $image->setType("image/jpeg");
        $image->setEncoding(Zend\Mime\Mime::ENCODING_BASE64);
        $image->setDisposition(Zend\Mime\Mime::DISPOSITION_ATTACHMENT);
        $image->setFileName('t.jpg');
        
        // 注意,作为一个附件,仅设置type是不够的,还需要设置文件名,根据文件后缀名了识别类型
        // 至少QQ邮箱是如此,一个Message有一个或多个Part,有一个Zend\Mime\Mime(啥毛?)
        // 多个Part作为内容输出时,需要合并在一起,这时Zend\Mime\Mime就用来参数分割线的了
        $excel = new MimePart(file_get_contents("D:/excel.xls"));
        $excel->setType("application/x-xls"); 
        $excel->setEncoding(Zend\Mime\Mime::ENCODING_BASE64);
        $excel->setDisposition(Zend\Mime\Mime::DISPOSITION_INLINE);
        $excel->setFileName('e.xls');
        $excel->setDescription("这是一个表格");
        $excel->setCharset("UTF-8");

        $body = new MimeMessage();
        $body->setParts(array($text, $html, $image));
        
        $message = new Message();
        $message->setBody($body); 
        */
       
        /* 文件transport
        $transport = new FileTransport();
        $options   = new FileOptions(array(
            // 只有两个参数
            'path'              => ROOT_PATH.'/mail/',
            'callback'  => function (FileTransport $transport) {
                return 'Message_' . microtime(true) . '_' . mt_rand() . '.txt';
            },
        ));
        $transport->setOptions($options);
        */
        
        /* 内存transport 无配置参数
        $transport = new InMemoryTransport();
        */
        
        // 2 启动  SmtpTransport
        $transport = new SmtpTransport();
        // 3 配置
        $options   = new SmtpOptions(array(
            'name'              => 'localhost',
            'host'              => 'smtp.qq.com',
            'port'              => 25,
            //默认是smtp, 测试plain, login都可以发信,但是smtp不行
            'connection_class'  => 'login', 
            'connection_config' => array(
                'username' => 'vfeelit@qq.com',
                'password' => 'xxxx',
                // “ssl” => “tls” and port 587 for TLS or “ssl” => “ssl” and port 465 for SSL.
                'ssl'    => 'tls'
            ),
        ));
        
        /* 
        // 普通配置
        $options   = new SmtpOptions(array(
            'name'              => 'localhost',
            'host'              => 'smtp.qq.com',
            'port'              => 25,
            'connection_class'  => 'plain',
            'connection_config' => array(
                'username' => 'vfeelit@qq.com',
                'password' => 'xxxxx'
            ),
        ));
         
        // 以下是一份ssl配置
        $options   = new SmtpOptions(array(
            'name'              => 'localhost',
            'host'              => 'smtp.qq.com',
            'port'              => 587,
            'connection_class'  => 'plain',
            'connection_config' => array(
                'username' => 'vfeelit@qq.com',
                'password' => 'xxxxx',
                'ssl'      => 'tls'
            ),
        ));
        */
        
        // 4 设置配置
        $transport->setOptions($options);

        // 5 发信
        $transport->send($message);
        
    }
}