Laravel(Mailtrap.io)批量发送含唯一注册令牌的邮件
Hey, I’ve dealt with this exact problem before—sending 20-25 individual emails via a synchronous foreach loop feels glacial because each send waits for a full round-trip to Mailtrap. The best solution here is to use Laravel's queue system to handle emails asynchronously, which drastically speeds up the process and frees your application to handle other requests.
1. Set Up a Queued Mailable
First, create a dedicated mailable class for your signup token emails to keep code clean and queue-ready:
php artisan make:mail SignupTokenMail
Open the generated file (app/Mail/SignupTokenMail.php) and update it to accept the signup token and pass it to your email view:
namespace App\Mail; use Illuminate\Bus\Queueable; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; class SignupTokenMail extends Mailable { use Queueable, SerializesModels; // Public property makes the token automatically available in the view public $signupToken; /** * Create a new message instance. * * @param string $signupToken * @return void */ public function __construct(string $signupToken) { $this->signupToken = $signupToken; } /** * Build the message. * * @return $this */ public function build() { return $this->view('emails.signup-token') ->subject('Your Unique Signup Token'); } }
2. Create the Email View
Make a blade template for your email at resources/views/emails/signup-token.blade.php:
<p>Hi there,</p> <p>Your unique signup token is: <strong>{{ $signupToken }}</strong></p> <p>Use this token to complete your registration.</p>
3. Configure Your Queue
For simplicity, use the database queue driver (no extra services required):
- Generate the queue jobs table:
php artisan queue:table php artisan migrate - Update your
.envfile to use the database queue:QUEUE_CONNECTION=database
4. Queue Emails Instead of Sending Synchronously
Replace Mail::send() with Mail::queue() in your loop. This adds jobs to the queue immediately instead of waiting for Mailtrap responses:
// Your array of emails and tokens (example) $userData = [ ['email' => 'user1@example.com', 'signup_token' => 'abc123'], ['email' => 'user2@example.com', 'signup_token' => 'def456'], // ... up to 25 entries ]; foreach ($userData as $user) { \Illuminate\Support\Facades\Mail::to($user['email']) ->queue(new \App\Mail\SignupTokenMail($user['signup_token'])); } // Optional: Delay sending (e.g., send in 5 minutes) // Mail::to($user['email'])->later(now()->addMinutes(5), new SignupTokenMail($user['signup_token']));
5. Run the Queue Worker
Start the queue worker to process pending email jobs. It runs in the background, reuses connections to Mailtrap, and handles jobs efficiently:
php artisan queue:work
For continuous operation (even after server restarts), use a process manager like Supervisor to keep the worker running.
Why This Is Faster
- Asynchronous Processing: Your app doesn’t wait for each email to send—jobs are added to the queue and processed in the background.
- Connection Reuse: The queue worker maintains a persistent connection to Mailtrap, avoiding the overhead of establishing a new connection for every email.
- Scalability: Even if your array grows beyond 25 entries, the queue system handles it smoothly.
Alternative: Optimized Synchronous Sending (Not Recommended)
If queues aren’t an option, reuse the SwiftMailer connection to cut down on overhead—but this is still slower than queues:
$mailer = \Illuminate\Support\Facades\Mail::getSwiftMailer(); $transport = $mailer->getTransport(); foreach ($userData as $user) { $message = (new \Swift_Message('Your Unique Signup Token')) ->setFrom(config('mail.from.address')) ->setTo($user['email']) ->setBody(view('emails.signup-token', ['signupToken' => $user['signup_token']])->render(), 'text/html'); $mailer->send($message); } // Close the transport connection when done $transport->stop();
内容的提问来源于stack exchange,提问作者Melvin Hagberg

