16

アプリケーションにメーリング リスト システムを実装しようとしています。私は現在Zend_Mail_Transport_Smtp('localhost')、サブスクライバーのリストをループし、それぞれに新しいを送信して、トランスポートとして使用していZend_Mailます。ただし、サブスクライバーの数が増えるにつれて、スクリプトが完了するまでにかかる時間が長くなることに気付きました。

これを行うには、電子メールのキューイングを含む、より専門的なアプローチが必要であると確信しています。理想的なアプローチは、何百通ものメールの送信が完了するのを待つのではなく、ユーザーがフォームに記入して送信をクリックすると、メールが送信されているという応答をすぐに受け取ることだと思います。

Zend_Mail私はそれがメールのキューイングを行わないことを理解しています。これを経験したことがある人は、これを行う方法の概要を教えてもらえますか? cron/crontab/cronjobs について何も知らないので、それが含まれる場合はプロセスを説明してください。

4

8 に答える 8

20

PHP を使用して大量のメールを確実に送信するには、キューイング メカニズムを使用する必要があります。他の人が示唆しているように、キューを使用するプロセスは次のようになります。

  • ユーザーのセットをループして、各ユーザーのメールを作成し、場合によってはコンテンツをカスタマイズします
  • 各メール オブジェクトをキューに渡します。これにより、電子メールの送信が遅くなります。
  • ある種の cron スクリプトで、一度に数百のキューの内容を送信します。注: 実際の送信プロセスから返されるエラーのログを監視して、送信する電子メールの数を微調整する必要があります。あまりにも多く送信しようとすると、メールトランスポートが接続を受け入れなくなるポイントに達することに気付きました (私は qmail を使用しています)。

これを行うために使用できるライブラリがいくつかあります。PEAR Mail Queue (Mail_Mime を使用) と SwiftMailer の両方を使用すると、電子メールを作成してキューに入れることができます。これまでのところ、Zend Mail はメールの作成のみを提供し、キューイングは提供していません (これについては後で詳しく説明します)。

私は主にPEAR Mail Queueの経験があり、いくつかの落とし穴があります。大量の電子メールをキューに入れようとしている場合 (たとえば、20,000 人以上のユーザーをループして、適切な時間内にキューに入れようとしている場合)、Mail Mime の quoted-printable エンコーディングの実装を使用すると非常に遅くなります。base64 エンコーディングに切り替えることで、これを高速化できます。

Zend Mail に関しては、Zend Mail オブジェクトを PEAR Mail Queue に入れる Zend Mail Transport オブジェクトを作成できます。私はこれをある程度成功させましたが、それを正しく行うには少し時間がかかります。これを行うには、Zend Mail Transport Abstract を拡張し、_sendMail メソッド (Zend Mail オブジェクトをメール キューにドロップする場所) を実装し、トランスポート オブジェクトのインスタンスを Zend Mail オブジェクトの send() メソッドに渡します。 Zend Mail::setDefaultTransport() による。

要するに、これを行うには多くの方法がありますが、それにはいくつかの調査と学習が必要です。ただし、これは非常に解決可能な問題です。

于 2009-05-07T02:36:36.253 に答える
20

注: あなたの質問を最初に読んだとき、一度に数十万件のメールが届いていると思いました。再確認したところ、実際には数百から数千と表示されていることに気付きました。私は怠惰すぎて今投稿を変更することができないので、ここにいくつかの注意点があります: 私の経験からすると、商用ツールがなくても 40K 程度までは問題なく動作する可能性があります。約 10K では、リストのサイズが大きくなり始めたときに大きな問題が発生しないように、「最小」リストに従うことをお勧めします。ただし、すべてをすぐに実装することをお勧めします。

前にも言いましたが、メールの送信には 2 つの側面があります。

  1. 技術的な側面 -- 基本的に、smtp プロトコル、電子メール形式、DNS レコードなどに関するすべての RFC です。これはやや複雑ですが、解決可能です。
  2. 魔法の側面 -- メール配信管理はブードゥー教です。あなたはイライラし、明白な理由もなく物事が壊れ、電子メールを含まない別の仕事に就くことを考えるでしょう.

独自の一括送信者を作成しないことをお勧めします。PHP がうまく機能すると確信していますが、他の場所で時間を費やすべきでしょう。私が過去に使用して推奨した 2 つの製品は、Strongmail と PowerMTA です。注意してください - それらは高額ですが、長い目で見れば、独自のソリューションを構築するためにより多くの費用がかかることはほぼ保証できます。

PHP で独自のコードを作成する際に釘付けになる領域の 1 つは、スロットリング/タール ピットです。メールサーバーは、あなたがいくつかのメッセージを送信した後、sleep(30) の追加を開始して、あなたの速度を落とし、スパム行為を止めます。

通常、これらの商用バルク送信者は、キューイングのために SMTP プロトコルを実行します。Zend_Mail を引き続き使用しますが、サーバーに接続するようにハード コードします。送信できる速さでメールをキューに入れ、独自のエンジンを使用して宛先にメールを送信します。

10 万件のリストでは、メールのベスト プラクティスを採用する必要があります。少なくとも、次のものが必要です。

  • SPF レコード、場合によっては DKIM も
  • トラフィックを分割するための複数の IP -- 信頼できる高品質のアドレス用に 1 つ、中リスクの IP アドレス用に 1 つ、高リスクの IP アドレス用に 1 つの 3 つの IP があります。この設計により、最適な顧客にメールが届くリスクを最小限に抑えることができます。
  • IP アドレスを送信するための適切な逆引き DNS
  • スパムの苦情を処理するために、AOL、hotmail、yahoo などからのフィードバック ループを使用します。
  • 登録解除とバウンス管理 -- これらのアドレスを削除していることを確認してください
  • 開封/クリックの追跡も重要です。A リストの顧客がメールを開封しない場合は、それらを B リストに格下げする必要があります。ISP は非アクティブなアカウントをハニーポットに変えてしまうため、これは重要です。Hotmailはこれで有名です。

最後に、メールの送信に真剣に取り組んでいる場合は、Return Path などの他のツールが必要になるでしょう。

于 2009-04-25T14:21:03.557 に答える
3

Zend_Queue を使用して、メールを非同期バックグラウンド処理のキューに入れます。バックグラウンドでキューを処理するには、cron ジョブが必要です。

protected function _enqueueEmail(WikiEmailArticle $email)
{
    static $intialized = false; 

    if (!$initialized) {

        $this->_initializeMailQueue("wikiappwork_queue");
        $initialized = true;
    }

    $this->_mailQueue->send(serialize($email));  
}
protected function _initializeMailQueue()
{
    /* See: 1.) http://framework.zend.com/manual/en/zend.queue.adapters.html and
     *      2.) Zend/Queue/Adapter/Db/mysql.sql. 
     */

 $ini = Zend_Controller_Front::getInstance()->getParam('bootstrap')
                                            ->getOptions(); 

     $queueAdapterOptions =    array( 'driverOptions' => array(
    'host' => $ini['resources']['multidb']['zqueue']['host'],
    'username' => $ini['resources']['multidb']['zqueue']['username'],
    'password' => $ini['resources']['multidb']['zqueue']['password'],
    'dbname' => $ini['resources']['multidb']['zqueue']['dbname'],
    'type' => $ini['resources']['multidb']['zqueue']['adapter'] ),
    'name' => $ini['resources']['multidb']['zqueue']['queueName'] );

    $this->_mailQueue = new Zend_Queue('Db', $queueAdapterOptions);

 }

次に、cronジョブの場合、次のようなスクリプト

<?php
use \Wiki\Email\WikiEmailArticle;

// Change this define to correspond to the location of the wikiapp.work/libary
define('APPLICATION_PATH', '/home/kurt/public_html/wikiapp.work/application');

set_include_path(implode(PATH_SEPARATOR, array(
     APPLICATION_PATH . '/../library',
     get_include_path(),
 )));

// autoloader (uses closure) for loading both WikiXXX classes and Zend_ classes.
spl_autoload_register(function ($className) { 

  // Zend classes need underscore converted to PATH_SEPARATOR
  if (strpos($className, 'Zend_' ) === 0) {

        $className = str_replace('_', '/', $className );   
  }

  $file = str_replace('\\', '/', $className . '.php');

  // search include path for the file.
  $include_dirs = explode(PATH_SEPARATOR, get_include_path());

  foreach($include_dirs as $dir) {

    $full_file = $dir . '/'. $file;

    if (file_exists($full_file)) { 

        require_once $full_file; 
        return true; 
    }
  }

  return false; 
 }); 

// Load and parese ini file, grabing sections we need.
$ini = new Zend_Config_Ini(APPLICATION_PATH . 
                          '/configs/application.ini', 'production');

$queue_config = $ini->resources->multidb->zqueue;

$smtp_config = $ini->email->smtp;

$queueAdapterOptions =  array( 'driverOptions' => array(
                                        'host'      => $queue_config->host,
                    'username'  => $queue_config->username,
                    'password'  => $queue_config->password,
                    'dbname'    => $queue_config->dbname,
                    'type'      => $queue_config->adapter),
                'name' => $queue_config->queuename);

$queue = new Zend_Queue('Db', $queueAdapterOptions);


$smtp = new Zend_Mail_Transport_Smtp($smtp_config->server, array(
                'auth'      => $smtp_config->auth,
        'username'  => $smtp_config->username,
        'password'  => $smtp_config->password,
        'port'      => $smtp_config->port,
        'ssl'       => $smtp_config->ssl
        ));

Zend_Mail::setDefaultTransport($smtp);

$messages = $queue->receive(10); 

foreach($messages as $message) {

        // new WikiEmailArticle.     
    $email = unserialize($message->body);

        try {

            $email->send();

        }  catch(Zend_Mail_Exception $e) {

               // Log the error?
               $msg = $e->getMessage();
               $str = $e->__toString();
               $trace =  preg_replace('/(\d\d?\.)/', '\1\r', $str);
        } // end try

$queue->deleteMessage($message);

} // end foreach
于 2011-05-26T00:07:49.063 に答える
3

PHP.net ドキュメントから。

注: mail() 関数は、ループ内の大量の電子メールには適していないことに注意してください。この関数は、電子メールごとに SMTP ソケットを開いたり閉じたりするため、あまり効率的ではありません。
大量の電子メールの送信については、 » PEAR::Mailおよび » PEAR::Mail_Queueパッケージを参照してください。

Zend Mail クラスはおそらくかなり優れています (Zend のもののほとんどは優れています)。ただし、他のオプションが必要な場合。どうぞ。

于 2009-04-25T12:29:59.220 に答える
2

私は、各メールが個人に合わせてカスタマイズされたphpでバルクメーラーを実装しました。難しくはなく、それほど時間もかかりませんでした。swiftmailerとcronを使用しました。ZendMailも大丈夫かもしれません。PEARメールキューから始めましたが、メールのキューイングが遅すぎました。

メールをキューに入れるプロセスは次のようになりました。

  1. メールテンプレートを作成し、一意のコンテンツが置き換えられる領域のプレースホルダーを追加します(またはテンプレートエンジンを使用します)。
  2. ループでは、プレースホルダーを任意の一意のコンテンツに置き換え、結果の電子メールコンテンツ、件名、アドレス、バッチID、およびオプションで優先度の値をデータベーステーブルに挿入します。

cronジョブを使用して、電子メールのバッチを送信しました。私は制限のある共有ホストを使用していたため、cronの時間間隔とバッチごとに送信される電子メールの数は重要でした。cronジョブによって呼び出されたスクリプトには、cronからのみアクセスできました。スクリプトは、バッチIDと、オプションで優先度の順に並べられたテーブルからx個の電子メールを読み取ります。電子メールが正常に送信された場合、データベースキューから削除されました。電子メールを送信できなかった場合、その電子メールはキューに残り、そのレコードのカウンターがインクリメントされました。カウンターが設定された数を超えた場合、電子メールはキューから削除されました。

于 2009-04-25T18:37:10.867 に答える
2

他の人が指摘しているように、mail() は避けてください。大量のメール (100,000 人以上の受信者) 用に設計されたシステムが、標準のメール機能を迂回して MTA をより直接的に操作しようとしているのを見てきました。それでも、それが必要かどうかは私にはわかりませんでした。

電子メールをプロフェッショナルにすることは、形式が適切であること (可能な限り HTML とプレーン テキスト)、人々が簡単に購読を解除できること、バウンスが正しく処理されること、メール サーバーにすべての適切な DNS レコードが配置されていること、およびサーバー構成が正しくないことを確認することです。主要なブラックリスト システムの規則に違反しない。アプリケーションを作成する言語は、メッセージ数が数百または数千の場合でも重要な要素ではありません。

于 2009-04-25T12:49:58.923 に答える
0

Swiftmailerを使用してニュースレター管理システムを開発しましたが、実装は非常に簡単です。SMTP、暗号化、添付ファイル、バッチ送信などをサポートしています...

于 2009-04-26T00:57:45.163 に答える