Problem:
If you are developing a web project that includes sending emails to users, then it is very important for you to know if those emails are being read or delivered to those users. For example, if you are sending marketing emails to your subscriber’s list, then it is essential for you to know that your email is read by which users. And by which users the email is not read yet.
This will greatly help you to make decisions if you are sending the right emails or not. Because if the user can read your marketing email, but didn’t buy anything from you, it clearly means there was something wrong with the email. But how do you know if the email sent from PHP, Laravel, or whatever framework you are using, is being opened by the user?
Solution:
Follow this tutorial, and you will be able to add such functionality in your web project.
Sending the email:
For sending the email, you can use the popular “PHPMailer” library. You can also use built-in PHP “mail()” function. Open command prompt or Terminal in your project root folder and run the following command (make sure you have composer installed in your system):
composer require phpmailer/phpmailer
This will create a “vendor” folder in your project root folder. Create a table in your MySQL database named “emails” and it will have 4 columns:
- ID (INTEGER) (primary key, auto_increment, not null)
- email (TEXT) (not null)
- content (TEXT) (not null)
- read_at (DATETIME) (null)
Send email using the following code in your PHP file:
<?php
// import PHPMailer classes into the global namespace
// these must be at the top of your script, not inside a function
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
// load Composer's autoloader
require 'vendor/autoload.php';
// instantiation and passing `true` enables exceptions
$mail = new PHPMailer(true);
// the person who will receive the email
$recipient = "recipient_email";
// content of email
$content = "This is the HTML message body <b>in bold!</b>";
// connect with database
$conn = mysqli_connect("localhost:8889", "root", "root", "test");
// insert in mails table
$sql = "INSERT INTO emails (email, content) VALUES ('" . $recipient . "', '" . $content . "')";
mysqli_query($conn, $sql);
// get inserted mail ID
$email_id = mysqli_insert_id($conn);
// append empty image tag with email content
// this will help to know when user read that email
$base_url = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$content .= "<img src='" . $base_url . "email_read.php?email_id=" . $email_id . "' style='display: none;' />";
try {
// disable verbose debug output
$mail->SMTPDebug = 0;
// send using SMTP
$mail->isSMTP();
// set the SMTP server to send through
$mail->Host = 'smtp.gmail.com';
// enable SMTP authentication
$mail->SMTPAuth = true;
// SMTP username
$mail->Username = 'your_email@gmail.com';
// SMTP password
$mail->Password = 'your_password';
// enable TLS encryption
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
// TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
$mail->Port = 587;
$mail->setFrom('your_email@gmail.com', 'Your name');
// add a recipient
$mail->addAddress($recipient);
// set email format to HTML
$mail->isHTML(true);
$mail->Subject = 'Here is the subject';
$mail->Body = $content;
$mail->send();
echo 'Message has been sent';
} catch (Exception $e) {
echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}
You just need to change the email and password with your Gmail address and password. To learn more about configuring an SMTP server, read this.
This is how the email will be received in the user’s inbox (image will not be visible):
View emails and time they are read:
Now, we will create a separate page for the admin where he/she can see a list of all emails sent from the website along with the time they are read by the user. Create a file named “view_emails.php” and paste the following code in it:
<?php
// connect with database
$conn = mysqli_connect("localhost:8889", "root", "root", "test");
// get all emails
$sql = "SELECT * FROM emails";
$result = mysqli_query($conn, $sql);
?>
<!-- basic style of table -->
<style>
table, td {
border: 1px solid black;
border-collapse: collapse;
padding: 25px;
}
</style>
<table>
<?php
// show all emails
while ($row = mysqli_fetch_object($result))
{
?>
<tr>
<td><?= $row->id; ?></td>
<td><?= $row->email; ?></td>
<td><?= $row->content; ?></td>
<td><?= $row->read_at == null ? "Not read" : $row->read_at; ?></td>
</tr>
<?php
}
?>
</table>
Access this page directly and you will see a list of all emails with the time they are read (next step).
Mark the time when email is read:
Create a file named “email_read.php” and paste the following code in it:
<?php
// this page will be executed only when the email is opened by user
// connect with database
$conn = mysqli_connect("localhost:8889", "root", "root", "test");
// get email ID
$email_id = $_GET["email_id"];
// update read_at value in emails table
$sql = "UPDATE emails SET read_at = NOW() WHERE id = '" . $email_id . "'";
mysqli_query($conn, $sql);
You will never see the output from this file but it will mark the time in database when the email is read.
Let me know if you had any problem in following this tutorial.