如何在2天后触发邮件发送?sleep()致页面脚本延迟的解决方案咨询
Using sleep() for long delays like 2 days is a terrible idea—here's why:
- It blocks the entire script, forcing the user to wait 2 full days for the page to load (which will never actually happen, since PHP has a maximum execution time limit, usually 30-60 seconds).
- If the server restarts, the script crashes, or the user closes their browser, the email will never be sent.
Instead, you need to decouple the email sending from the user's request. Here are two reliable methods to do this:
Method 1: Database Queue + Cron Job (Most Reliable)
This is the standard approach for scheduled tasks. We'll store the email details in a database, then have a recurring script check for pending emails to send.
Step 1: Create a Pending Emails Table
First, make a table in your database to hold the emails waiting to be sent:
CREATE TABLE pending_emails ( id INT AUTO_INCREMENT PRIMARY KEY, to_email VARCHAR(255) NOT NULL, subject VARCHAR(255) NOT NULL, message TEXT NOT NULL, headers TEXT NOT NULL, send_at DATETIME NOT NULL, is_sent BOOLEAN DEFAULT FALSE );
Step 2: Save Email to Queue When User Submits
Instead of sending the email immediately, insert it into the table with a send_at timestamp set to 2 days from now:
// Your existing variables $subject = "Application Enquiry Details"; $to = $email; // Assume $email is validated/sanitized $headers = "MIME-Version: 1.0\r\n"; $headers .= "Content-type: text/html; charset=iso-8859-1\r\n"; $headers .= "From: noreply \r\n"; $message = "your application is received"; // Calculate send time: current time + 2 days $sendAt = date('Y-m-d H:i:s', strtotime('+2 days')); // Insert into database (use prepared statements to prevent SQL injection!) $pdo = new PDO('mysql:host=your_host;dbname=your_db', 'user', 'pass'); $stmt = $pdo->prepare("INSERT INTO pending_emails (to_email, subject, message, headers, send_at) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$to, $subject, $message, $headers, $sendAt]); // Tell the user their submission was successful immediately echo "Thank you! We'll send a confirmation email in 2 days.";
Step 3: Write a Script to Send Pending Emails
Create a standalone PHP script (e.g., send_scheduled_emails.php) that checks for unsent emails where send_at is in the past:
<?php $pdo = new PDO('mysql:host=your_host;dbname=your_db', 'user', 'pass'); // Get all unsent emails that need to be sent now $stmt = $pdo->prepare("SELECT * FROM pending_emails WHERE is_sent = FALSE AND send_at <= NOW()"); $stmt->execute(); $emails = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($emails as $email) { // Send the email $sent = mail($email['to_email'], $email['subject'], $email['message'], $email['headers']); // Mark as sent if successful if ($sent) { $updateStmt = $pdo->prepare("UPDATE pending_emails SET is_sent = TRUE WHERE id = ?"); $updateStmt->execute([$email['id']]); } } ?>
Step 4: Set Up a Cron Job
Schedule the send_scheduled_emails.php script to run periodically (e.g., every 5 minutes) using a cron job. On Linux, edit your crontab with crontab -e and add:
*/5 * * * * /usr/bin/php /path/to/your/send_scheduled_emails.php
This runs the script every 5 minutes, checking for any emails that are due to be sent.
Method 2: Use the at Command (One-Time Scheduling)
If your server supports the at command (common on Linux), you can schedule a one-time execution of the email script.
Step 1: Create a Temporary Script for the Email
When the user submits, generate a temporary PHP file with the email details:
// Your existing variables $subject = "Application Enquiry Details"; $to = $email; $headers = "MIME-Version: 1.0\r\n"; $headers .= "Content-type: text/html; charset=iso-8859-1\r\n"; $headers .= "From: noreply \r\n"; $message = "your application is received"; // Escape variables to prevent shell injection $escapedTo = escapeshellarg($to); $escapedSubject = escapeshellarg($subject); $escapedMessage = escapeshellarg($message); $escapedHeaders = escapeshellarg($headers); // Create a temporary script $tempScript = "/tmp/send_email_" . uniqid() . ".php"; file_put_contents($tempScript, <<<EOT <?php mail($escapedTo, $escapedSubject, $escapedMessage, $escapedHeaders); unlink(__FILE__); // Delete the script after running EOT ); // Make the script executable chmod($tempScript, 0755); // Schedule it to run in 2 days using `at` exec("echo '/usr/bin/php $tempScript' | at now + 2 days"); // Confirm to user echo "Thank you! We'll send a confirmation email in 2 days.";
⚠️ Security Note: Always escape variables when using exec() to prevent shell injection attacks. Also, make sure the /tmp directory is secure on your server.
Why These Methods Are Better
- They don't block the user's request—your page loads immediately.
- They're reliable even if the server restarts (the cron job will pick up where it left off).
- They respect PHP's execution time limits.
内容的提问来源于stack exchange,提问作者Jobie

