Send email with attachments from folder on web server

Hi,

Hope this makes sense and hope someone can help me.

I have a database table with the following columns: person_id, firstname, surname, email_address.

Periodically I am given a set of files to send to some of the contacts in the database table. The filenames contain the person_id and they are always of the format: person_id.pdf or person_id-2.pdf. Sometimes there is only one of the files available or sometimes it is both of the files. The files are stored in a directory on our server

Example.
directory: letters
files: 1111.pdf, 1111-2.pdf, 2222.pdf, 3333-2.pdf

The user with person_id 1111: should receive an email with two attachements - 1111.pdf and 1111-2.pdf
The user with person_id 2222: should receive an email with one attachement - 2222.pdf
The user with person_id 3333-2: should receive an email with one attachement - 3333-2.pdf

This is just a small example, in real world scenario it could be hundreds of users to send these files to so I need an automated way using PHP to acheive this.

I have got to a point where:
The user with person_id 2222: receives the correct email
The user with person_id 3333: receives the correct email
However the user with person_id 1111: always receives two emails containing the same content.

I think this is because both files exist so whilst executing the loop it is doing it once for each file so my logic is flawed and I can’t figure it out.

The way my file is built is:

Use PHPMailer

Make data connection

Submit button - once clicked:

loops through my letters directory to find the files
set filenames as variables to use
use substr on the filename to extract the person_id
run db query to retrieve relevant record where person_id = “filename” (minus the .pdf or -2.pdf)
attach relevant files and send email.

I have attached a copy of my code to hopefully show what I am trying to acheive.

Please ask if you would like further clarification. My code so far is embedded below

I am aware my PHP may have all sorts of errors or non best practice methods but I am learning all time

Kind Regards
Mr Dello

Link to my PHP code

A. Your link didn’t work for me (says it is expired.)
B. You should be able to post code using bbcode code tags. Here’s what it is from the raw data from your edit -

<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
use setasign\Fpdi\Fpdi;

require 'PHPMailer/src/Exception.php';
require 'PHPMailer/src/PHPMailer.php';
require 'PHPMailer/src/SMTP.php';

//configure database access
	$dbuser = 'user';
	$dbpass = 'pass';
	$database = 'database';
	$dbserver = 'servername';
	$db = mysqli_connect($dbserver, $dbuser, $dbpass, $database)
	or die ('Database not available');

if(!isset($_POST['submitted'])){
	//display form if not submitted
	print "<p><strong>Press submit to send letters</p>";
	?>
	<form name="" action="test.php" method="POST">
		<input name="submitted" type="hidden" value="submitted">
		<input name="submit" type="submit" value="Post Letters">
	</form>
	<?php
}else{
	$dir = "letters";
	if (is_dir($dir)){
	  if ($dh = opendir($dir)){
		while (($file = readdir($dh)) !== false){
			if (strstr($file,".pdf")){
				$number++;
				$letter1 = "letters/".substr($file,0,4).".pdf";
				$letter2 = "letters/".substr($file,0,4)."-2.pdf";
				if(strstr($file,"-2.pdf")){
				
				}else{
					sendMail($db,$letter1,$letter2);
				}
	
			} 
		}
		closedir($dh);
	  }
	}else{
		echo "No directory found";
	}
}


function sendMail($db,$letter1,$letter2){

	$personid = substr($letter1,8,4);
	
	$query = "SELECT person_id, forename, surname, email_address FROM people_table WHERE person_id = ".$personid;
	
	$result = mysqli_query($db,$query) or die (mysqli_error()."<br> Query error");
			while($row = mysqli_fetch_array($result)){
				$sforename = $row['forename'];
				$ssurname = $row['surname'];
				$emailaddress = $row['email_address'];
			}
	
	$bodytext = "
		<p>
		Dear ".$sforename." ".$ssurname.",
		</p>
		<p>
			HTML Formatted email with attachments
		</p>
	    Best wishes,<br><br>		
		";
	

	$email = new PHPMailer();
	$email->IsHTML(true);
	$email->From      = 'admin@business.com';
	$email->FromName  = 'Admin Office';
	$email->Subject   = 'Important Letter for: '.$personid;
	$email->Body      = $bodytext;
	$email->AddAddress = $emailaddress;
	
	if(file_exists($letter2)){
		
		$email->AddAttachment( $letter2 , $personid."-letter2.pdf" );
		$email->AddAttachment( $letter1, $personid."-letter1.pdf" );

	}else{
	
		$email->AddAttachment( $letter1, $personid."-letter1.pdf" );
	}
	
	return $email->Send();
}

?>

Even if your application will never have more than two files at a time for a user, you should write the code to be general purpose. See the following example code, which uses the php PDO database extension, that should (untested) work -

// define the email body 'template'
$bodytext = 
"<p>Dear %s %s,</p>
<p>HTML Formatted email with attachments</p>
Best wishes,<br><br>
";

$dir = "letters";

if(!isset($_POST['submitted'])){
	//display form if not submitted
	print "<p><strong>Press submit to send letters</p>";
	?>
	<form method="POST">
		<input name="submitted" type="hidden">
		<input type="submit" value="Post Letters">
	</form>
	<?php
}else{
	if (!is_dir($dir))
	{
		echo "No directory found";
	} else {
		// dir exists
		$files = glob("$dir/*.pdf"); // returns files alphabetically sorted. the format is: letters/1111-2.pdf
		
		// pre-processes the data, indexing it using the id
		$data = [];
		foreach($files as $file)
		{
			preg_match('~/(.*?)[-\.]~', $file, $matches); // get the value between the / and the - or the .
			$id = $matches[1];
			$data[$id][] = $file;
		}

		// prepare the query once before the start of any looping
		$sql = "SELECT forename, surname, email_address FROM people_table WHERE person_id = ?";
		// note: this example uses the much simpler php PDO extension, rather than the mysqli extension
		$stmt = $pdo->prepare($sql);
		
		foreach($data as $id=>$arr)
		{
			$stmt->execute([$id]); // query for the user's data
			$row = $stmt->fetch(); // fetch the row of data
			// populate the body 'template'
			$body = sprintf($bodytext, htmlentities($row['forename'],ENT_QUOTES),htmlentities($row['surname'],ENT_QUOTES));
			
			// do your php mailer calls
			$email = new PHPMailer();
			$email->IsHTML(true);
			$email->From      = 'admin@business.com';
			$email->FromName  = 'Admin Office';
			$email->Subject   = 'Important Letter for: '.$id; // since the id is/should be numeric, there's no good reason to include it here
			$email->Body      = $body; // this is changed from your original code
			$email->AddAddress = $row['email_address'];

			// loop over the file(s) for the user
			foreach($arr as $fn)
			{
				$email->AddAttachment($fn, basename($fn));
			}
			
			$email->Send();
		}
	}
}

Hi,

Thanks so much for your advice. I didn’t know anything about PDO and it was not enabled on my server (PHP 5.6.3) but I added the php_pdo_mysql extension and amended your code to suit my environment. However I get the following error in the log files and the code doesn’t execute:

PHP Notice:  Undefined variable: pdo

I receive the error on this line:

$stmt = $pdo->prepare($sql);

Kind Regards
Mr Dello

So what’s unclear now? You didn’t define what $pdo is. CTRL+F in here doesn’t show any code.

Hi,

My response was to user phdr .

He gave me some code to try and when I tried it, PHP threw an error about PDO not being being defined. I am not familiar with PDO so trying to resolve the error so I can carry on testing the code.

Kind Regards
Mr Dello

PDO is PHP Data Object, it is the preferred way of interacting with the database.

1 Like

Thank you, I will look through all the information

Sponsor our Newsletter | Privacy Policy | Terms of Service