Swift Wrapper Class

Swift Mailer is a fantastic library for sending email with php. Discuss this library or ask any questions about it here.

Moderators: Chris Corbyn, General Moderators

Post Reply
mpetrovich
Forum Commoner
Posts: 55
Joined: Fri Oct 19, 2007 2:02 am
Location: Vancouver, WA, USA

Swift Wrapper Class

Post by mpetrovich »

Below is my new Swift wrapper class for Version 4. I would love any critique. This class can be extended for specific uses, but in its simplest form lets you send messages quite easily. We use it to send single messages, and batch messages as well.

Here are some notes:
  • There are two main functions: SendMessage, and SendMail. SendMail is quite similar to the PHP mail function. SendMessage is used if you manually set all the parameters
  • Email format is checked. I allow entry of emails in array format, and comma delimited lists (email1,email2... or name:email..., or name<email>...).
  • I compress HTML messages, removing extra space.
  • This only uses SMTP or Sendmail options. If you use SMTP, you have to set the parameters after you instantiate the class with the SetSmtp() function
  • This will take html only content and then try to create text content by stripping the tags. This needs more work.
  • There are two function to for attachments: SetAttachedFiles, and SetAttachedDynamicFiles
  • It tries to get a return path from a list or array, if you do not set it as a single email
  • GetMessageDetails() is for debugging purposes.
So, I have been using this for about a week, and it seems to work pretty well. Any thoughts, comments, or critique would be welcome.

Code: Select all

 
class MailSwift
{
    protected $Subject     = '';
    protected $Body_Text   = '';
    protected $Body_Html   = '';
    protected $Body_Html_Raw = '';
    protected $From        = '';
    protected $To          = '';
    protected $Cc          = '';
    protected $Bcc         = '';
    protected $Attachment  = '';
    protected $Return_Path = '';
 
    protected $Transport   = '';
    protected $Mailer      = '';
    protected $Smtp                  = array();
    protected $Attached_Files        = array();
    protected $Attached_Dynamic_Files= array();
    protected $Text_Headers          = array();
 
    protected $Message;
 
    public    $Error          = '';
    public    $Error_Extended = '';
 
 
    // add translations as necessary for this text
    public    $Text_Messages  = array (
        'ATTACHMENT_NOT_FOUND'  => 'Attachment not found',
        'BAD_EMAIL_RETURN_PATH' => 'Bad Email Return Path',
        'BAD_EMAIL'             => 'Bad Email',
        'MESSAGE_FAILED'        => 'Message Failed',
        'TRANSPORT_FAILED'      => 'Transport Failed to Initialize'
    );
 
    
    // function to check if email has valid form
    public function CheckEmail($email)
    {
        $last_dot  = strrpos($email, '.');
        $at_sign   = strrpos($email, '@');
        $at_groups = explode('@', $email);
        $length    = strlen($email);
        $bad_email = (
            (count($at_groups) != 2) || ($last_dot===false) || ($at_sign===false) || ($length===false)||
            ($last_dot - $at_sign < 2) || ($length - $last_dot < 3) || ($at_sign == 0)
            );
        return !$bad_email;
    }
 
    // function to add to error string
    protected function AddError($error)
    {
        $this->Error .= "$error<br />\n";
    }
 
    // function to set SMTP parameters, could be called in construct of child classes
    public function SetSmtp($smtp, $username, $password, $port=25)
    {
        $this->Smtp = array(
            'smtp'     => $smtp,
            'username' => $username,
            'password' => $password,
            'port'     => $port
        );
    }
 
    // function to set subject
    public function SetSubject($subject)
    {
        // remove HTML special characters from subject
        $subject = htmlspecialchars_decode($subject);
        $this->Subject = $subject;
    }
 
 
    // function to remove extra spaces in HTML code
    public function CompressHtml($html)
    {
        $E = chr(27);
        //trim and replace line breaks with escape character
        $RESULT = mb_ereg_replace("[\r\n|\n]+", $E, trim($html));
 
        //compress spaces
        $RESULT = mb_ereg_replace("[[:space:]]+", ' ', $RESULT);
 
        //remove space around line breaks
        $RESULT = mb_ereg_replace("{$E}[[:space:]]+", $E, $RESULT);
        $RESULT = mb_ereg_replace("[[:space:]]+$E", $E, $RESULT);
 
        //restore line breaks, removing multiples
        $RESULT = mb_ereg_replace("$E+", "\n", $RESULT);
 
        return $RESULT;
    }
 
 
    // function to set html body
    public function SetBodyHtml($text)
    {
        // raw is uncompressed
        $this->Body_Html_Raw = $text;
        $this->Body_Html = $this->CompressHtml($text);
    }
 
    // function to set text body
    public function SetBodyText($text)
    {
        $this->Body_Text = $text;
    }
 
    // function to set text body from HTML
    public function SetBodyTextFromHtml()
    {
        // strip tags is only a start, other transforms are needed, such as links
        $text = strip_tags($this->Body_Html_Raw);
        $this->Body_Text = $text;
    }
 
    // function to check to see if a file attachment exists
    protected function CheckAttachmentExists($attachment)
    {
        if (file_exists($attachment)) {
            return true;
        } else {
            $this->AddError($this->Text_Messages['ATTACHMENT_NOT_FOUND'] . " ($attachment)");
            return false;
        }
    }
 
    // function to set attachment files
    public function SetAttachedFiles($attachments)
    {
        // assumes an array of file links or a single attachment
        if ($attachments) {
            if (is_array($attachments)) {
                foreach ($attachments as $attachment) {
                    if ($this->CheckAttachmentExists($attachment)) {
                        $this->Attached_Files[] = $attachment;
                    }
                }
            } else {
                if ($this->CheckAttachmentExists($attachments)) {
                    $this->Attached_Files[] = $attachments;
                }
            }
        } else {
            $this->Attached_Files = array();
        }
    }
 
 
    // function to attach dynamic content
    public function SetAttachedDynamicFiles($attachments)
    {
        // requires an array  of rows: ('data', 'filename', 'type')
        if ($attachments) {
            if (is_array($attachments[0])) {
                $this->Attached_Dynamic_Files = $attachments;
            } else {
                // must be a single item
                $this->Attached_Dynamic_Files[] = $attachments;
            }
        } else {
            $this->Attached_Dynamic_Files = array();
        }
    }
 
    // function to set custom headers
    public function SetTextHeaders($headers)
    {
        // assumes an associative array of header-name => value
        if ($headers and is_array($headers)) {
            foreach ($headers as $name => $value) {
                $this->Text_Headers[$name] = $value;
            }
        } else {
            $this->Text_Headers = array();
        }
    }
 
 
    // function to get emails to set, can take arrays or comma delimited lists
    protected function GetEmails($list)
    {
        if ($list) {
            if (is_array($list)) {
                return $list;
            } else {
                //comma delimited list in: name:email,... || email1,email2..., ||  name <email>,. . . 
                $emails = explode(',', $list);
                $RESULT = array();
                foreach ($emails as $email) {
                    $email = trim($email);
                    if (strpos($email, '<') !== false) {
                        // --- get name <email> format ---
                        $email_part = trim(preg_replace('/.+<|>/', '', $email));                        
                        $name  = trim(preg_replace('/<.+/', '', $email));
                        $email = $email_part;
                    } else {                    
                        $parts = explode(':', $email);
                        // --- get name:email format ---
                        if (count($parts) > 1) {
                            $name  = trim($parts[0]);
                            $email = trim($parts[1]);
                        } else {
                            $name = '';
                        }
                    }
                    
                    if ( $this->CheckEmail($email) ) {
                        if ($name) {
                            $RESULT[$email] = $name;
                        } else {
                            $RESULT[] = $email;
                        }
                    } else {
                        $this->AddError($this->Text_Messages['BAD_EMAIL'] . ": $email");
                    }
                }
                return $RESULT;
            }
        } else {
            return '';
        }
    }
 
    // function to set TO
    public function SetTo($to)
    {
        $this->To = $this->GetEmails($to);
    }
 
    // function to set FROM
    public function SetFrom($from)
    {
        $this->From = $this->GetEmails($from);
    }
 
    // function to set CC
    public function SetCc($cc)
    {
        $this->Cc = $this->GetEmails($cc);
    }
 
    // function to set BCC
    public function SetBcc($bcc)
    {
        $this->Bcc = $this->GetEmails($bcc);
    }
 
 
    // function to set the return path
    public function SetReturnPath($return_path)
    {
        if (is_array($return_path)) {
            foreach ($return_path as $key => $value) {
                if ($this->CheckEmail($key)) {
                    $this->Return_Path = $key;
                } elseif ($this->CheckEmail($value)) {
                    $this->Return_Path = $value;
                } else {
                    $this->Return_Path = '';
                    $this->AddError($this->Text_Messages['BAD_EMAIL_RETURN_PATH']);
                }
                return;
            }
        } elseif ($this->CheckEmail($return_path)) {
            $this->Return_Path = $return_path;
        } else {
            $this->Return_Path = '';
            if (!empty($return_path)) {
                $this->AddError($this->Text_Messages['BAD_EMAIL_RETURN_PATH']);
            }
        }
    }
 
 
 
    // function to instantiate the transport and mailer, if not already set, check for SMTP, otherwise uses sendmail
    public function SetTransportAndMailer()
    {
        if (!$this->Transport) {
            try {
            
                if (!empty($this->Smtp)) {
                    $this->Transport = Swift_SmtpTransport::newInstance($this->Smtp['smtp'], $this->Smtp['port'])
                        ->setUsername($this->Smtp['username'])
                        ->setPassword($this->Smtp['password']);
                } else {
                    $this->Transport = Swift_SendmailTransport::newInstance('/usr/sbin/sendmail -bs');
                }
                return $this->Mailer = Swift_Mailer::newInstance($this->Transport);
                
            } catch(Exception $e) {
                $this->AddError($this->Text_Messages['TRANSPORT_FAILED']); // message to public
                $this->Error_Extended = $e->getMessage();  // message for admin
                return false;
            }
        }
    }
 
 
    // function to output email details for diagnosis, used in function below
    protected function GetEmailDetails($email, $title='')
    {
        $RESULT = '';
        if (is_array($email)) {
            foreach ($email as $key => $value) {
                $RESULT .= "<dt>$title:</dt><dd>$key => $value</dd>\n";
            }
        } else {
            $RESULT .= "<dt>$title:</dt><dd>$email</dd>\n";
        }
        return $RESULT;
    }
 
    // function to output message details for diagnosis, using a definition list
    public function GetMessageDetails()
    {
        $RESULT  = '<dl>';
        $RESULT .= $this->GetEmailDetails($this->From, 'From');
        $RESULT .= $this->GetEmailDetails($this->To, 'To');
 
        if ($this->Cc) {
            $RESULT .= $this->GetEmailDetails($this->Cc, 'Cc');
        }
 
        if ($this->Bcc) {
            $RESULT .= $this->GetEmailDetails($this->Bcc, 'Bcc');
        }
 
        if ($this->Return_Path) {
            $RESULT .= $this->GetEmailDetails($this->Return_Path, 'Return Path');
        }
 
        if ($this->Text_Headers) {
            $RESULT .= "<dt>Custom Headers:</dt><dd>\n<ul>\n";
            foreach ($this->Text_Headers as $name => $value) {
                $RESULT .= "<li>$name: $value</li>\n";
            }
            $RESULT .= "</ul>\n</dd>";
        }
 
        $RESULT .= "<dt>Subject:</dt><dd>{$this->Subject}</dd>\n";
        $RESULT .= "<dt>HTML:</dt><dd>{$this->Body_Html}</dd>\n";
        $RESULT .= "<dt>Text:</dt><dd><pre>{$this->Body_Text}</pre></dd>\n";
 
        if ($this->Attached_Files) {
            $RESULT .= "<dt>Attachments:</dt><dd>\n<ul>\n";
            foreach ($this->Attached_Files as $attachment) {
                $RESULT .= "<li>$attachment</li>\n";
            }
            $RESULT .= "</ul>\n</dd>";
        }
 
        if ($this->Attached_Dynamic_Files) {
            $RESULT .= "<dt>Dynamic Attachments:</dt><dd>\n<ul>\n";
            foreach ($this->Attached_Dynamic_Files as $attachment) {
                //$data     = $attachment[0];
                $filename = $attachment[1];
                $type     = $attachment[2];
                $RESULT .= "<li>$filename, $type</li>\n";
            }
            $RESULT .= "</ul>\n</dd>";
        }
 
        return $RESULT;
    }
 
    // function to send a message pulling from the class variables
    public function SendMessage()
    {
        try {
            $message = Swift_Message::newInstance()
            ->setSubject($this->Subject)
            ->setFrom($this->From)
            ->setTo($this->To);
 
            if(!$this->Return_Path) {
                $this->SetReturnPath($this->From);
            }
            $message->setReturnPath($this->Return_Path);
 
            if ($this->Cc) {
                $message->setCc($this->Cc);
            }
 
            if ($this->Bcc) {
                $message->setBcc($this->Bcc);
            }
 
            if ($this->Text_Headers) {
                foreach ($this->Text_Headers as $name => $value) {
                    $message->getHeaders()->addTextHeader($name, $value);
                }
            }
 
            if ($this->Attached_Files) {
                foreach ($this->Attached_Files as $attachment) {
                    $message->attach(Swift_Attachment::fromPath($attachment));
                }
            }
 
            if($this->Attached_Dynamic_Files) {
                foreach ($this->Attached_Dynamic_Files as $attachment) {
                    $data     = $attachment[0];
                    $filename = $attachment[1];
                    $type     = $attachment[2];
                    $message->attach(Swift_Attachment::newInstance($data, $filename, $type));
                }
            }
 
            if ($this->Body_Html) {
                $body_html = Swift_MimePart::newInstance( $this->Body_Html, 'text/html' );
                $message->attach($body_html, 'text/html');
            }
 
            if (empty($this->Body_Text) and $this->Body_Html) {
                $this->SetBodyTextFromHtml();
            }
 
            $body_text = Swift_MimePart::newInstance( $this->Body_Text, 'text/plain' );
            $message->addPart($this->Body_Text, 'text/plain');
 
            $this->SetTransportAndMailer();
            return $this->Mailer->send($message);
 
        } catch (Exception $e) {
            $this->AddError($this->Text_Messages['MESSAGE_FAILED']); // message to public
            $this->Error_Extended = $e->getMessage();  // message for admin
            return false;
        }
 
    }
 
 
    // general function to send a messages, sets the basics,  will need to set attachments, special headers, and SMTP before this function is called
    public function SendMail($from, $to, $subject, $message_html='', $message_text='', $bounce='', $cc='', $bcc='')
    {
        $error_point = 0;
        try {
            $this->Error = '';
            $this->Error_Extended = '';
 
            $this->SetFrom($from);
            $this->SetTo($to);
            $this->SetCc($cc);
            $this->SetBcc($bcc);
            $this->SetSubject($subject);
            $this->SetBodyHtml($message_html);
            $this->SetBodyText($message_text);
            $this->SetReturnPath($bounce);
            $error_point = 1;
            return $this->SendMessage();
 
        } catch (Exception $e) {
            if ($error_point == 0) {
                // this means error occurred before SendMessage(), so need to add errors, otherwise errors already added
                $this->AddError($this->Text_Messages['MESSAGE_FAILED']); // message to public
                $this->Error_Extended = $e->getMessage();  // message for admin
            }
            return false;
        }
    }
}
echoDreamz
Forum Newbie
Posts: 9
Joined: Sat Feb 21, 2009 7:54 am

Re: Swift Wrapper Class

Post by echoDreamz »

Love it! We too developed a wrapper around the SwiftMailer objects, yours has a few more options though. Very good, would love to see proper Zend commenting for the method docs.
Post Reply