My websites (or something?) continues to resend emails months after they were originally sent.

My websites (or something?) continues to resend emails months after they were originally sent. This is a really weird problem that has effected multiple websites and it is driving me crazy. The details:

Several of my websites use code just like this -

<?php 
include 'session.php';
require_once('class.phpmailer.php');
?>

<!doctype html>
<div class="container">
<?php
$r_id = $_GET["r_id"];
$query2 = "SELECT r_code, idcustomers FROM property WHERE r_id = '" . $r_id . "'";	
$results2 = mysqli_query($conn, $query2);
$row2 = mysqli_fetch_array($results2);
$r_code = $row2["r_code"];
$idcustomers = $row2["idcustomers"];
$query = "SELECT email FROM customers WHERE idcustomers = '" . $idcustomers . "'";	
$results = mysqli_query($conn, $query);
$row = mysqli_fetch_array($results);
$email = $row["email"];
if ($email == '') {echo "Customer does not have a valid email address on file! Hit the back button.";}
else {
?>

<?php 
$mail = new PHPMailer();
$mail->IsSMTP(); 
$mail->SMTPDebug  = 0;
$mail->SMTPAuth   = true;                  
$mail->SMTPSecure = "ssl";    
$mail->IsHTML(true);
$mail->Host = "smtp.gmail.com";
$mail->Port = 465;
$mail->Username = "xxx@gmail.com";
$mail->Password   = "xxx";   
$mail->SetFrom('cgmboats@gmail.com', 'Central Georgia Marina');
$mail->AddReplyTo("cgmboats@gmail.com","Central Georgia Marina");
$mail->Subject    = "Your Central Georgia Boat Space Rental Invoice";
$mail->AltBody    = "To view the message, please use an HTML compatible email viewer!"; // optional, comment out and test

$mail_body = '<html>
<head>
</head>
<body>
<p>Please click <a href="https://cgmserver.com/boat_space_rental_inv.php?r_code=' . $r_code . '" >here</a> to view and print your recent invoice
</body>
</html>';

$mail->MsgHTML($mail_body);
$mail->AddAddress($email);

if(!$mail->Send()) {
  echo "Mailer Error: " . $mail->ErrorInfo;
} else {
  echo "Email has been sent. Return to <a href=\"index.php\">Main Page</a>";
}

$mail->clearAddresses();
?>
<?php  };//End of ????>
</div>

Open in new window


Some sites use the phpmailer to send emails after "Contact Us" forms are filled out. Either way it is basic phpmailer.

In some scenarios my clients will either receive repeat form submissions 3-6 months after the original email was sent. The will just get another copy in their inbox. In the case of the code above it actually sends repeat invoices (batches at a time) to customers. The last time was today and it re-sent invoices from 5 months ago. CRAZY!!!

This is what I have tried so far:

Originally I used the SMTP service on my VPS. I switch to using SMTP.com. - No help!
I switched from SMTP.com to using Google SMTP service - No Help
I have switch hosting servers - No help

The above code is run when they press an email button on a SINGLE invoice page. They don't have the ability to batch send emails. Yet something on this earth is taking batches of emails that were sent in the past and sending them again. This is a huge problem that I have been trying to resolve for over 18 months. I have searched the internet high and low and no one seems to have this problem.

Just to add to the crazyness, on one of the pages I list all of the current service orders they are working on. Sometimes when the above action happens this said page becomes blank (meaning all the service orders have a status of complete). The only way to change the status of an order is to run this page:

<?php include 'session.php';?>
<!doctype html>
<head>
<meta charset="utf-8">
<title>Update Status</title>
</head>
<body>
<div class="container">
<h2>Update Work Order Status</h2>
<br>
<form name="so_status" method="post" action="">
<p>
  <label for="so_status">Status</label>
  <select style="margin-left:15px;" name="so_status">
	  <option></option>
    <option value="In-Service">In-Service</option>
    <option value="Waiting for Parts">Waiting for Parts</option>
    <option value="Ready for Billing Review">Ready for Billing Review</option>
    <option value="Ready for Customer">Ready for Customer</option>
    <option value="Complete">Complete</option>
	</select>
</p>
<p>
  <input type="submit" name="btnSubmit" value="Update">
</p>
  <?php
		$so_id = $_GET['so_id'];
  if (isset($_POST['btnSubmit'])) { //Does not display data until button is submitted
		$so_status = $_POST['so_status'];
		$query = "UPDATE service SET so_status = '" . $so_status . "' WHERE so_id = '" . $so_id . "' ";	
	    $results = mysqli_query($conn, $query);
		header("Location: marine_service_order_list.php?sort=so_created");
  ?>
  <?php ;} //End of button submit ?>
</div>
</body>
</html>

Open in new window


This page will change the status of service order ONE AT A TIME yet some how all the service orders are set to complete the next morning. This is just out of the blue every couple of months.

Please help
Robert FrancisDirector of Continuous ImprovementAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Mal OsborneAlpha GeekCommented:
Are you certain that the problem is the website sendig multiple copies?

I notice you are using Gmail. The user is not, by chance pullling email from a Gmail mailbox via POP3?

POP3 is notorious for deliverign multiple copies of emails, due to the way the protocol works. Unless a POP3 session is properly terminated, it will not delete email, but will leave them sitting there until the next session.
Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
It is possible what Mal is saying. However, I suggest making a few updates to your site.

  • Separate your php code from your html.
  • Accept post data instead of get for items that will cause action such as sending out an email.
  • Make sure data you accept is sanitized.
  • Use prepared statements in your sql and not concatenations.
  • Add Cross Site Scripting protection.

As an example of the first item, move your mailer function to a separate page.

<?php 

if(isset($_POST)){

   $email = $_POST['email'];

} else {
 die();
}



$sentFrom = 'cgmboats@gmail.com', 'Central Georgia Marina'

$mail_body = '<html>
<head>
</head>
<body>
<p>Please click <a href="https://cgmserver.com/boat_space_rental_inv.php?r_code=' . $r_code . '" >here</a> to view and print your recent invoice
</body>
</html>';


$mail = new PHPMailer();
$mail->IsSMTP(); 
$mail->SMTPDebug  = 0;
$mail->SMTPAuth   = true;                  
$mail->SMTPSecure = "ssl";    
$mail->IsHTML(true);
$mail->Host = "smtp.gmail.com";
$mail->Port = 465;
$mail->Username = "xxx@gmail.com";
$mail->Password   = "xxx";   
$mail->SetFrom($sentFrom);
$mail->AddReplyTo("cgmboats@gmail.com","Central Georgia Marina");
$mail->Subject    = "Your Central Georgia Boat Space Rental Invoice";
$mail->AltBody    = "To view the message, please use an HTML compatible email viewer!"; // optional, comment out and test

$mail->MsgHTML($mail_body);
$mail->AddAddress($email);

if(!$mail->Send()) {
  echo "Mailer Error: " . $mail->ErrorInfo;
} else {
  echo "Email has been sent. Return to <a href=\"index.php\">Main Page</a>";
}

$mail->clearAddresses();

Open in new window


I would enhance the above further by making  a function where you can post data and reuse the mail code for everything. Then you don't have to have multiple files.  

Instead of actually posting via a form, use ajax to post to the page and make sure you are preventing the page from being posted to by accident or maliciously. http://phpsecurity.readthedocs.io/en/latest/Cross-Site-Scripting-(XSS).html  https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
Robert FrancisDirector of Continuous ImprovementAuthor Commented:
Mel - POP3 is not involved and we just switched the smtp service to Google two weeks ago. This has been going on with multiple websites, servers, and smtp services.

Scott - The main reason why I avoid using EE until the bitter end is that when I post questions like this is people can't help but to completely ignore the question and go straight to why I suck at coding. And I get it. I do. And I will take all the stuff you said and learn from it. I will. But right now I need someone to specifically resolve why exact copies of emails are magically being emailed out months after they were originally created.

Lets start simple. A visitor goes to a website and fills out a form with 4 text boxes. They hit a submit button. Those 4 values are sent to a page like above that takes that information, puts it in an email, and sends it to my client. Now remember, those 4 values are NOT saved in a database. Lets fast forward 6 months. That same email with those same 4 values appears in my clients email box again. HOW? Is this a caching issue?
CompTIA Security+

Learn the essential functions of CompTIA Security+, which establishes the core knowledge required of any cybersecurity role and leads professionals into intermediate-level cybersecurity jobs.

Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
> people can't help but to completely ignore the question

Robert, I'm sorry you feel that way and I should have been more detailed in why I posted what I did.  What I feel could be happening is your code may allow somebody to hit the original url there were on 6 months ago and cause the very issue you are seeing.  The recommendations I made are only meant to help prevent what is going on.

By separating the code that does the work from the code that presents the visuals it will be easier to enforcing some type of safeguard against accidental surfing to a link that pushes out your email.

Does that sound right?  Can you recreate the issue of emails going out by sending yourself a legit email, then go back to the same email a 2nd or 3rd time and hit the same link?  

With troubleshooting it is a matter of trial and error to find the issue.  I like to eliminate all possible issues even if one of those items didn't fix it. That's all I am trying to help with.  I'm sorry it came off wrong.
Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
> Those 4 values are sent to a page like above that takes that information, puts it in an email, and sends it to my client. .... ...HOW? Is this a caching issue?

You have a link in the email.  Does that link allow you to resend over an over if you click on it?  That was the point I was trying to make.
Robert FrancisDirector of Continuous ImprovementAuthor Commented:
Scott - If I understand you correctly you are suggesting that I go in the direction of MVC for separation of code. Also, I wanted to be sure that what was causing this problem was either a technical error on my part or someone being malicious. A technical error could be quickly fixed but having to recode an entire site is probably not going to happen. It seems that the efforts one must take to prevent hackers is not worth being in the business anymore.
Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
You don't have to go complete MVC.  You can think of the options as procedural, functional and MVC.  Functional is a little of both and will be much easier to transition into.

I am not suggesting changing all of your pages, just this part that is causing issues.  And even that is not completely mandatory but will make it easier for you in the long run.

What I do think you need to do is test to see if it is possible to surf to the page with that link and each time the page loads with the link, is the email notification being sent?  That would be the first thing to test if you have already eliminated the possibility it is the user's email/POP.

If that does end up being the case that just hitting the link or the user has the thing bookmarked or in the browser history, there are ways you can ensure the email is not sent out by mistake such as what I have suggested.

Looking at  your first bit of code you have
r_id = $_GET["r_id"];

Open in new window

Does this mean somebody can go to yoursite.com/page.php?r_id=123 and if the r_id is correct then the query will run
SELECT r_code, idcustomers FROM property WHERE r_id = '" . $r_id . "'"

Open in new window

And eventually you get to
$email = $row["email"];
if ($email == '') {echo "Customer does not have a valid email address on file! Hit the back button.";}
else {
// RUN THE CODE TO GENERATE AN EMAIL

Open in new window


If that is the case where I can surf to that page with a valid r_id, then it is possible that could be at least part of the problem.

Another option you can do to make sure only one email goes out is to add a field in your table property for "email_sent" which can be a timestamp.  Set it to null. When the email goes out, run an update query that adds the current time stamp.  Then on your line 10 above in the first code snippet
$query2 = "SELECT r_code, idcustomers FROM property WHERE r_id = '" . $r_id . "'";	

Open in new window

Change $query2 to make sure the field email_sent is null. That will prevent this from firing.

I do think in the end if just for this portion, you updated the page to separate and force some type of post with special code to make sure it was supposed to happen, it will be easier for you to manage in the long run.  Then the other recommendation I have is to parameterize which prevents sql injections. PHP makes this very simple and the adjustment to your code is minor. All of us have had that, "learning experience".  And giving you the recommendation is not saying anything bad about you, just a friendly reminder from somebody that has already been through that.

For now, just test to see if it is possible to surf to the page with the link in the email and generate an unwanted email send. If that is the case, we can go from there.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Robert FrancisDirector of Continuous ImprovementAuthor Commented:
Scott - I have debated for years whether I would force myself to learn MVC. I have tried several times and it feels like switching from right handed to left handed. I have been studying Codeigniter for the last couple of days and maybe something has clicked. While this is not the exact solution you gave you did help push me with some of your comments. Thanks.
Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
I'm glad that worked out.  Check, out codecademy for a quick interactive overview too. https://www.codecademy.com/courses/web-beginner-en-bH5s3/0/1
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.