Shoora
4/28/2019 - 10:10 PM

A mail class to generate and send an email (with attachments).

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();