A mail class to generate and send an email (with attachments).
<?php
/**
* Class to generate and send an mail (with attachments).
* Needs PHP >= 5.3.0 (for finfo class and idn_to_ascii function).
* @author Sebastian Brosch <sebastian.brosch@brosch-software.de>
* @copyright 2014 Sebastian Brosch
* @license http://www.gnu.org/licenses/gpl-3.0.html GNU GPL Version 3
* @version 1.0.0
*/
class Email
{
/**
* Additional parameters for sending the mail (4th parameter of mail function).
* @see http://php.net/manual/en/function.mail.php
* @since 1.0.0
* @var string $additionalParameter
*/
private $additionalParameter = '';
/**
* Collection of all attachments.
* @since 1.0.0
* @var array $attachments
*/
private $attachments = array();
/**
* Collection of all BCC (Blind Copy Carbon) mail-addresses.
* @since 1.0.0
* @var array $bcc
*/
private $bcc = array();
/**
* Collection of all CC (Copy Carbon) mail-addresses.
* @since 1.0.0
* @var array $cc
*/
private $cc = array();
/**
* The formatted content (HTML) of the mail.
* @since 1.0.0
* @var string $contentHTML
*/
private $contentHTML = '';
/**
* The plain content (non HTML) content of the mail.
* @since 1.0.0
* @var string $contentPlain
*/
private $contentPlain = '';
/**
* Collection of all receivers.
* @since 1.0.0
* @var array $receivers
*/
private $receivers = array();
/**
* The mail-address on which should be answered.
* @since 1.0.0
* @var string $replyTo
*/
private $replyTo = '';
/**
* The sender of the mail.
* @since 1.0.0
* @var string $sender
*/
private $sender = '';
/**
* The subject of the mail.
* @since 1.0.0
* @var string $subject
*/
private $subject = '';
/**
* Method to add a new attachment path to the collection.
* @param string $attachment The path to the attachment.
* @since 1.0.0
* @throws Exception if the attachment was not found.
*/
public function addAttachment($attachment)
{
//Check if the path of the attachment was found.
if(file_exists($attachment) === true) {
//Check if the attachment is already in the collection.
if(in_array($attachment, $this->attachments) === false) {
$this->attachments[] = $attachment;
}
} else {
throw new Exception('Attachment not found: '.$attachment);
}
}
/**
* Method to add a new BCC (Blind Copy Carbon) to the collection.
* @param string $bcc The new BCC of the mail.
* @since 1.0.0
* @throws Exception if the BCC mail-address is not valid.
*/
public function addBCC($bcc)
{
//Check if the BBC mail-address is valid.
if($this->isValidAddress($bcc) === true) {
//Check if the receiver is already in the collection.
if(in_array($bcc, $this->bcc) === false) {
$this->bcc[] = $bcc;
}
} else {
throw new Exception('Invalid bcc mail-address: '.$bcc);
}
}
/**
* Method to add a new CC (Carbon Copy) to the collection.
* @param string $cc The new mail-address for CC.
* @since 1.0.0
* @throws Exception if the CC mail-address is not valid.
*/
public function addCC($cc)
{
//Check if the CC mail-address is valid.
if($this->isValidAddress($cc) === true) {
//Check if the CC mail-address is already in the collection.
if(in_array($cc, $this->cc) === false) {
$this->cc[] = $cc;
}
} else {
throw new Exception('Invalid cc mail-address: '.$cc);
}
}
/**
* Method to add a new receiver mail-address to the collection.
* @param string $receiver The new receiver of the mail.
* @since 1.0.0
* @throws Exception if the receiver mail-address is not valid.
*/
public function addReceiver($receiver)
{
//Check if the receiver mail-address is valid.
if($this->isValidAddress($receiver) === true) {
//Check if the receiver is already in the collection.
if(in_array($receiver, $this->receivers) === false) {
$this->receivers[] = $receiver;
}
} else {
throw new Exception('Invalid receiver mail-address: '.$receiver);
}
}
/**
* Method to check if a mail-address is valid.
* @param string $address The mail-address which will be checked.
* @return boolean The state if the address is valid.
* @since 1.0.0
*/
public function isValidAddress($address)
{
//Check if the address is valid with plain address validation.
if(filter_var($address, FILTER_VALIDATE_EMAIL) !== false) {
return true;
}
//Check if the address is valid with punycoded address validation.
if(filter_var(idn_to_ascii(utf8_encode($address)), FILTER_VALIDATE_EMAIL) !== false) {
return true;
}
//Return the state.
return false;
}
/**
* Method to prepare an attachment for sending with mail.
* @param string $attachment The path to the attachment which will be prepared.
* @return string / boolean The prepared attachment of false if an error occurred.
* @since 1.0.0
*/
public function prepareAttachment($attachment)
{
//Check if the attachment path is valid.
if(file_exists($attachment) === true) {
//Get the file info of the attachment.
$fileInfo = new finfo(FILEINFO_MIME_TYPE);
$fileType = $fileInfo->file($attachment);
//Get the content of the attachment.
$file = fopen($attachment, "r");
$fileContent = fread($file, filesize($attachment));
$fileContent = chunk_split(base64_encode($fileContent));
fclose($file);
//Prepare the content of the attachment for mail and return result.
$msgContent = 'Content-Type: '.$fileType.'; name='.basename($attachment)."\r\n";
$msgContent .= 'Content-Transfer-Encoding: base64'."\r\n";
$msgContent .= 'Content-ID: <'.basename($attachment).'>'."\r\n";
$msgContent .= "\r\n".$fileContent."\r\n\r\n";
return $msgContent;
}
//Return the state.
return false;
}
/**
* Method to reset the receiver(s) and content information of the object for using the same instance.
* @since 1.0.0
*/
public function reset()
{
//Reset the receiver(s) and content informations.
$this->cc = array();
$this->bcc = array();
$this->receivers = array();
$this->attachments = array();
$this->contentHTML = '';
$this->contentPlain = '';
}
/**
* Method to generate and send the mail.
* @return boolean The state if the mail was successfully send.
* @since 1.0.0
*/
public function send()
{
//Check if a sender is available.
if(trim($this->sender) === '') {
return false;
}
//Check if one or more receiver is available.
if((is_array($this->receivers) === false) || (count($this->receivers) < 1)) {
return false;
}
//Generate boundaries for mail content areas.
$boundaryMessage = md5(rand().'message');
$boundaryContent = md5(rand().'content');
//Set the header informations of the mail.
$headers = array();
$headers[] = 'MIME-Version: 1.0';
$headers[] = 'X-Mailer: PHP/'.phpversion();
$headers[] = 'Date: '.date('r', $_SERVER['REQUEST_TIME']);
$headers[] = 'X-Originating-IP: '.$_SERVER['SERVER_ADDR'];
$headers[] = 'Content-Type: multipart/related;boundary='.$boundaryMessage;
$headers[] = 'Content-Transfer-Encoding: 8bit';
$headers[] = 'From: '.$this->sender;
$headers[] = 'Return-Path: '.$this->sender;
//Check if a Reply-To mail-address is available.
if(trim($this->replyTo) !== '') {
$headers[] = 'Reply-To: '.$this->replyTo;
} else {
$headers[] = 'Reply-To: '.$this->sender;
}
//Check if a BCC mail-address is available.
if((is_array($this->bcc) === true) && (count($this->bcc) > 0)) {
$headers[] = 'Bcc: '.implode(', ', $this->bcc);
}
//Check if a CC mail-address is available.
if((is_array($this->cc) === true) && (count($this->cc) > 0)) {
$headers[] = 'Cc: '.implode(', ', $this->cc);
}
//Start to generate the content of the mail.
$msgContent = "\r\n".'--'.$boundaryMessage."\r\n";
$msgContent .= 'Content-Type: multipart/alternative; boundary='.$boundaryContent."\r\n";
//Check if a plain content is available and add to content.
if(trim($this->contentPlain) !== '') {
$msgContent .= "\r\n".'--'.$boundaryContent."\r\n";
$msgContent .= 'Content-Type: text/plain; charset=ISO-8859-1'."\r\n";
$msgContent .= "\r\n".$this->contentPlain."\r\n";
}
//Check if a html content is available and add to content.
if(trim($this->contentHTML) !== '') {
$msgContent .= "\r\n".'--'.$boundaryContent."\r\n";
$msgContent .= 'Content-Type: text/html; charset=ISO-8859-1'."\r\n";
$msgContent .= "\r\n".$this->contentHTML."\r\n";
}
//Close the message area of the mail.
$msgContent .= "\r\n".'--'.$boundaryContent.'--'."\r\n";
//Add the attachments to the mail.
foreach($this->attachments as $attachment) {
$attachmentContent = $this->prepareAttachment($attachment);
//Check if the attachment could prepared for adding to the mail.
if($attachmentContent !== false) {
$msgContent .= "\r\n".'--'.$boundaryMessage."\r\n";
$msgContent .= $attachmentContent;
}
}
//Close the area of the whole mail content.
$msgContent .= "\r\n".'--'.$boundaryMessage.'--'."\r\n";
//Create a comma-separated list of all receivers.
$receivers = implode(',', $this->receivers);
//Send the mail and return state.
return mail($receivers, $this->subject, $msgContent, implode("\r\n", $headers), $this->additionalParameter);
}
/**
* Method to set an additional parameter for the mail function (4th parameter).
* @param string $parameter The additional parameter.
* @see http://php.net/manual/en/function.mail.php
* @since 1.0.0
*/
public function setAdditionalParameter($parameter)
{
$this->additionalParameter = $parameter;
}
/**
* Method to set the formatted content (HTML) of the mail.
* @param string $content The formatted content of the mail.
* @since 1.0.0
*/
public function setContentHTML($content)
{
$content = wordwrap($content, 70, "\n");
$this->contentHTML = $content;
}
/**
* Method to set the plain content of the mail.
* @param string $content The plain content of the mail.
* @since 1.0.0
*/
public function setContentPlain($content)
{
$content = wordwrap($content, 70, "\n");
$this->contentPlain = $content;
}
/**
* Method to set the Reply-To information of the mail-header.
* @param string $reply_to The reply-to mail-address of the mail.
* @since 1.0.0
* @throws Exception if the reply-to mail-address is not valid.
*/
public function setReplyTo($reply_to)
{
//Check if the Reply-To mail-address is valid.
if($this->isValidAddress($reply_to) === true) {
$this->replyTo = $reply_to;
} else {
throw new Exception('Invalid reply-to mail-address: '.$reply_to);
}
}
/**
* Method to set the sender of the mail.
* @param string $sender The sender of the mail.
* @since 1.0.0
* @throws Exception if the sender mail-address is not valid.
*/
public function setSender($sender)
{
//Check if the sender mail-address is valid.
if($this->isValidAddress($sender) === true) {
$this->sender = $sender;
} else {
throw new Exception('Invalid sender mail-address: '.$sender);
}
}
/**
* Method to set the subject of the mail.
* @param string $subject The subject of the mail.
* @since 1.0.0
*/
public function setSubject($subject)
{
$this->subject = $subject;
}
}
<?php
require_once('email.class.php');
//Example #1: mail with plain content.
$mail = new Email();
//Set subject and sender of the mail.
$mail->setSubject('Example mail');
$mail->setSender('john.doe@example.com');
//Set the plain content of the mail.
$mail->setContentPlain('Example plain-content!');
//Add a receiver of the mail (you can add more than one receiver too).
$mail->addReceiver('mike.doe@example.com');
//Finally send the mail.
$mail->send();
//Example #2: mail with html content.
$mail = new Email();
//Set subject and sender of the mail.
$mail->setSubject('Example mail');
$mail->setSender('john.doe@example.com');
//Set html-content for message.
$contentHTML = '
<html>
<head>
<title>Example mail</title>
</head>
<body>
<p>This is the content of the example mail.</p>
</body>
</html>';
//You can set a html content too (it will be override plain content).
$mail->setContentHTML($contentHTML);
//Add a receiver of the mail (you can add more than one receiver too).
$mail->addReceiver('mike.doe@example.com');
//Finally send the mail.
$mail->send();
//Example #3: mail with attachment.
$mail = new Email();
//Set subject and sender of the mail.
$mail->setSubject('Example mail');
$mail->setSender('john.doe@example.com');
//Add an attachment to the mail.
$mail->addAttachment('path/to/file.txt');
//Set the plain content of the mail.
$mail->setContentPlain('Example plain-content!');
//Add a receiver of the mail (you can add more than one receiver too).
$mail->addReceiver('mike.doe@example.com');
//Finally send the mail.
$mail->send();