Laravel9のMailableで送信前&送信後のMessage-Idを取得する
Laravel9
% php artisan --version
Laravel Framework 9.44.0
まず答えから。
<?php
namespace App\Events;
use Illuminate\Mail\Events\MessageSent;
use Illuminate\Support\Facades\Log;
use Symfony\Component\Mime\Message;
class OnMessageSent {
public function handle(MessageSent $event)
{
// とりあえずコレとっとけばOK
$id = $event->sent->getMessageId();
// Laravelが生成するMessage-IDも取得したい場合
$local_message_id = null;
$orig = $event->sent->getOriginalMessage();
if ($orig instanceof Message) {
$local_message_id = $orig->getPreparedHeaders()->get('Message-ID')->getBodyAsString();
}
//Log::info($event->sent->getDebug());
Log::info('real_smtp_id='.$id."\t".'local_smtp_id='. $local_message_id);
}
}
<?php
namespace App\Providers;
use App\Events\OnMessageSent;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Mail\Events\MessageSent;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* @var array<class-string, array<int, class-string>>
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
/* ↓追加 */
MessageSent::class=>[
OnMessageSent::class
],
];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
//
}
/**
* Determine if events and listeners should be automatically discovered.
*
* @return bool
*/
public function shouldDiscoverEvents()
{
return false;
}
}
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class TestEmail extends Mailable
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the message envelope.
*
* @return \Illuminate\Mail\Mailables\Envelope
*/
public function envelope()
{
return new Envelope(
subject: 'Test Email',
);
}
/**
* Get the message content definition.
*
* @return \Illuminate\Mail\Mailables\Content
*/
public function content()
{
return new Content(
view: 'email.dummy',
);
}
/**
* Get the attachments for the message.
*
* @return array
*/
public function attachments()
{
return [];
}
}
Hello.
ログ
local.INFO: real_smtp_id=MlTFAbRjSeaWDcGIscbqkg local_smtp_id=<0225de0cb4b78e5b2fea7567a6321904@example.com>
以上。
ログも取得したいなら$event->sent->getDebug()で取得可能
< 220 SG ESMTP service ready at geopod-ismtpd-4-0
> EHLO [127.0.0.1]
< 250-smtp.sendgrid.net
< 250-8BITMIME
< 250-PIPELINING
< 250-SIZE 31457280
< 250-STARTTLS
< 250-AUTH PLAIN LOGIN
< 250 AUTH=PLAIN LOGIN
> STARTTLS
< 220 Begin TLS negotiation now
> EHLO [127.0.0.1]
< 250-smtp.sendgrid.net
< 250-8BITMIME
< 250-PIPELINING
< 250-SIZE 31457280
< 250-STARTTLS
< 250-AUTH PLAIN LOGIN
< 250 AUTH=PLAIN LOGIN
> AUTH LOGIN
< 334 ...
> YXBpa2V5
< 334 ...
> ..
< 235 Authentication successful
> MAIL FROM:<hello@example.com>
< 250 Sender address accepted
> RCPT TO:<test@gmail.com>
< 250 Recipient address accepted
> DATA
< 354 Continue
> .
< 250 Ok: queued as bgPXyQjSTT2yy-5Rvj8PRA
php artisan tinker
use App\Mail\TestEmail;
$a = Mail::to('xxxx@example.com')->send(new TestEmail());
dd($a);
-raw: Symfony\Component\Mime\RawMessage {#3707
-message: """
From: Laravel <hello@example.com>\r\n
To: test@gmail.com\r\n
Subject: Test Email\r\n
Message-ID: <7bb34b09a49584f934895e1e305b5a41@example.com>\r\n
MIME-Version: 1.0\r\n
Date: Fri, 13 Jan 2023 15:14:06 +0000\r\n
Content-Type: text/html; charset=utf-8\r\n
Content-Transfer-Encoding: quoted-printable\r\n
\r\n
Hello.\r\n
"""
...
-messageId: "0iqWppCFTYOmGIKsVSK3Yg"
-debug: """
> MAIL FROM:<hello@example.com>\n
< 250 Sender address accepted\r\n
> RCPT TO:<test@gmail.com>\n
< 250 Recipient address accepted\r\n
> DATA\n
< 354 Continue\r\n
> .\n
< 250 Ok: queued as 0iqWppCFTYOmGIKsVSK3Yg\r\n
"""
}
ここでSendGridを利用した場合のMessage-Idを確認してみます
<SendGridが生成する識別情報を利用する方法>
Web API v3またはSMTPをご利用の場合で、独自の識別情報を付与する必要がなければ、自動で生成される「X-Message-ID」および「SendGrid Message ID」をご利用ください。
SendGridは送信リクエストを受け付けると、リクエストごとにX-Message-IDを生成します。この情報は、送信リクエストのレスポンスとして返却されます。その後メール送信処理が始まると、メールごとにSendGrid Message IDが付与されます。SendGrid Message IDは発生したイベントの各データに含まれます。
SendGrid Message IDは、X-Message-IDの後ろに各メールの識別用の文字列を付加した形になっています。そのため、X-Message-IDとSendGrid Message IDを送信側で保持しておけば、送信リクエストと発生した各イベントデータを紐付けることができます。
https://support.sendgrid.kke.co.jp/hc/ja/articles/360000222542
SendGrid経由で届いたメールのヘッダのMessage-IDは、SendGrid側で再生成されたものが利用されるようです。
From: Laravel <hello@example.com>
Subject: Test Email
Message-ID: <7bb34b09a49584f934895e1e305b5a41@example.com>
MIME-Version: 1.0
Date: Fri, 13 Jan 2023 15:14:07 +0000 (UTC)
X-Feedback-ID: 2864175:SG
自社のPostfixとかSendGridとかメール配信プロバイダを混合させる場合は2つのMessage-IDを保持したほうがよさそうです。
Laravel8
SwiftMailerのヘンで正しいMessageIdを返却しないので
ヘッダのバケツリレーまたはSwift_Events_SendListenerを補足するか、など
大変なので頑張ってください。
なお、SwiftMailerのサポートは終了しています。
Discussion