Updated SwiftMailer(4.xx) component with attachments and plugins

by sky_l3ppard
This version of SwiftMailer component is built under cake conventions and has ability to add attachments, plugins and SMTP under TLS or SSL. Also if you are using utf-8 characters Outlook uses different encoding for subject, so there is a possibility to change encoding for both: subject and message. In this version message is wrapped like in cake's email component etc. email element is wrapped in the email layout for a content type used. I must mention that SwiftMailer library is under GPL license. Thanks to Matt Huggins who was first to make this component under SwiftMailer version 3.xx

Changes

2.30

Requirements

  • PHP 5.2 or higher
  • openssl php extension if you use SSL or TLS
  • Limited network access to connect to remote SMTP servers

Step 1: downloading SwiftMailer

Download the latest version of SwiftMailer library from http://swiftmailer.org/download

Extract it somewhere on your machine, then copy all files from SwiftMailer library in the lib folder to your /app/vendors/swift_mailer/ directory

Now your vendors catalog should look like this:

/vendors
    /swift_mailer
        /classes
        /dependency_maps
        mime_types.php
        preferences.php
        swift_init.php
        swift_required.php

Notice: this article is created using SwiftMailer 4.05 version

Step 2: adding SwiftMailer component

Now copy the following component code and create file swift_mailer.php in your /app/controllers/components directory

Component Class:

<?php 
// File -> app/controllers/components/swift_mailer.php

/** 
 * SwiftMailer Component based on 4.05 version,
 * this component is inspired by Matt Hugins the developer of
 * SwiftMailer v.3 component based on 3.xx version.
 * 
 * @author Gediminas Morkevicius
 * @version 2.30
 * @license MIT
 * @category Components
 */

//required third party library "SwiftMailer" under GPL license 
App::import('Vendor''Swift', array('file' => 'swift_mailer'.DS.'swift_required.php'));

class 
SwiftMailerComponent extends Object {
    
/**
     * Reference to controller
     * 
     * @var Object
     * @access Private
     */    
    
var $__controller null;
    
/**
     * List of plugins to load then sending email
     * 
     * @var Array - list of plugins in pairs $pluginName/array($arg[0], $arg[...)
     * @access Private
     */    
    
var $__plugins = array();
    
/**
     * Email layout
     * 
     * @var String
     * @access Public
     */    
    
var $layout 'default';
    
/**
     * Path to the email template
     * 
     * @var String
     * @access Public
     */    
    
var $viewPath 'email';
    
/**
     * Send message as type:
     *         "html" - content type "html/text"
     *         "text" - content type "text/plain"
     *         "both" - both content types are included 
     * 
     * @var String
     * @access Public
     */    
    
var $sendAs 'both';
    
/**
     * Charset for message body
     * 
     * @var String
     * @access Public
     */    
    
var $bodyCharset 'utf-8';
    
/**
     * Charset for message subject
     * 
     * @var String
     * @access Public
     */    
    
var $subjectCharset 'utf-8';
    
/**
     * SMTP Security type: 
     *         "ssl" - security type
     *         "tls" - security type
     * 
     * @var String
     * @access Public
     */    
    
var $smtpType null;
    
/**
     * SMTP Username for connection
     * 
     * @var String
     * @access Public
     */     
    
var $smtpUsername '';
    
/**
     * SMTP Password for connection
     * 
     * @var String
     * @access Public
     */     
    
var $smtpPassword '';
    
/**
     * SMTP Host name connection
     * 
     * @var String
     * @access Public
     */     
    
var $smtpHost '';
    
/**
     * SMTP port (e.g.: 25 for open, 465 for ssl, etc.)
     * 
     * @var Integer
     * @access Public
     */     
    
var $smtpPort 25;
    
/**
     * Seconds before timeout occurs
     * 
     * @var Integer
     * @access Public
     */     
    
var $smtpTimeout 10;
    
/**
     * Sendmail command (e.g.: '/usr/sbin/sendmail -bs')
     * 
     * @var String
     * @access Public
     */     
    
var $sendmailCmd null;
    
/**
     * Email from address
     * 
     * @var String
     * @access Public
     */     
    
var $from null;
    
/**
     * Email from name
     * 
     * @var String
     * @access Public
     */     
    
var $fromName null;
    
/**
     * Recipients
     * 
     * @var Mixed
     *         Array - address/name pairs (e.g.: array(example@address.com => name, ...)
     *         String - address to send email to
     * @access Public
     */     
    
var $to null;
    
/**
     * CC recipients
     * 
     * @var Mixed
     *         Array - address/name pairs (e.g.: array(example@address.com => name, ...)
     *         String - address to send email to
     * @access Public
     */     
    
var $cc null;
    
/**
     * BCC recipients
     * 
     * @var Mixed
     *         Array - address/name pairs (e.g.: array(example@address.com => name, ...)
     *         String - address to send email to
     * @access Public
     */     
    
var $bcc null;
    
/**
     * List of files that should be attached to the email.
     *
     * @var array - list of file paths
     * @access public
     */
    
var $attachments = array();
    
/**
     * When the email is opened, if the mail client supports it 
     * a notification will be sent to this address
     * 
     * @var String - email address for notification
     * @access Public
     */     
    
var $readNotifyReceipt null;
    
/** 
     * Reply to address
     * 
     * @var Mixed
     *         Array - address/name pairs (e.g.: array(example@address.com => name, ...)
     *         String - address to send reply to
     * @access Public
     */
    
var $replyTo null
    
/**
     * Max length of email line
     * 
     * @var Integer - length of line
     * @access Public
     */
         
    
var $maxLineLength 78;
    
/**
     * Array of errors refreshed after send function is executed
     * 
     * @var Array - Error container
     * @access Public
     */
    
var $postErrors = array();
    
    
/**
     * Initialize component
     * 
     * @param Object $controller reference to controller
     * @access Public
     */
    
function initialize(&$controller) {
        
$this->__controller $controller;
    }
    
    
/**
     * Retrieves html/text or plain/text content from /app/views/elements/$this->viewPath/$type/$template.ctp
     * and wraps it in layout /app/views/layouts/$this->viewPath/$type/$this->layout.ctp
     * 
     * @param String $template - name of the template for content
     * @param String $type - content type:
     *         html - html/text
     *         text - plain/text
     * @return String content from template wraped in layout
     * @access Protected
     */
    
function _emailBodyPart($template$type 'html') {
        
$viewClass $this->__controller->view;

        if (
$viewClass != 'View') {
            if (
strpos($viewClass'.') !== false) {
                list(
$plugin$viewClass) = explode('.'$viewClass);
            }
            
$viewClass $viewClass 'View';
            
App::import('View'$this->__controller->view);
        }
        
$View = new $viewClass($this->__controllerfalse);
        
$View->layout $this->layout;
        
        
$content $View->element($this->viewPath.DS.$type.DS.$template, array('content' => ""), true);
        
$View->layoutPath $this->viewPath.DS.$type;
        
$content $View->renderLayout($content);
        
        
// Run content check callback
        
$this->__runCallback($content'checkContent');
        
        return 
$content;
    }
    
    
/**
     * Sends Email depending on parameters specified, using method $method,
     * mail template $view and subject $subject
     * 
     * @param String $view - template for mail content
     * @param String $subject - email message subject
     * @param String $method - email message sending method, possible values are:
     *         "smtp" - Simple Mail Transfer Protocol method
     *         "sendmail" - Sendmail method http://www.sendmail.org/
     *         "native" - Native PHP mail method
     * @return Integer - number of emails sent
     * @access Public
     */
    
function send($view 'default'$subject ''$method 'smtp') {
        
// Check subject charset, asuming we are by default using "utf-8"
        
if (strtolower($this->subjectCharset) != 'utf-8') {
            if (
function_exists('mb_convert_encoding')) {
                
//outlook uses subject in diferent encoding, this is the case to change it
                
$subject mb_convert_encoding($subject$this->subjectCharset'utf-8');
            }
        }
        
// Check if swift mailer is imported
        
if (!class_exists('Swift_Message')) {
            throw new 
Exception('SwiftMailer was not included, check the path and filename');
        }
        
        
// Create message
        
$message Swift_Message::newInstance($subject);
        
        
// Run Init Callback
        
$this->__runCallback($message'initializeMessage');
        
        
$message->setCharset($this->subjectCharset);
        
        
// Add html text
        
if ($this->sendAs == 'both' || $this->sendAs == 'html') {
            
$html_part $this->_emailBodyPart($view'html');
            
$message->addPart($html_part'text/html'$this->bodyCharset);
            unset(
$html_part);
        }
        
        
// Add plain text or an alternative
        
if ($this->sendAs == 'both' || $this->sendAs == 'text') {
            
$text_part $this->_emailBodyPart($view'text');
            
$message->addPart($text_part'text/plain'$this->bodyCharset);
            unset(
$text_part);
        }
        
        
// Add attachments if any
        
if (!empty($this->attachments)) {
            foreach(
$this->attachments as $attachment) {
                if (!
file_exists($attachment)) {
                    continue;
                }
                
$message->attach(Swift_Attachment::fromPath($attachment));
            }
        }
        
        
// On read notification if supported
        
if (!empty($this->readNotifyReceipt)) {
            
$message->setReadReceiptTo($this->readNotifyReceipt);
        }
        
        
$message->setMaxLineLength($this->maxLineLength);
        
        
// Set the FROM address/name.
        
$message->setFrom($this->from$this->fromName);
        
// Add all TO recipients.
        
if (!empty($this->to)) {
            if (
is_array($this->to)) {
                foreach(
$this->to as $address => $name) {
                    
$message->addTo($address$name);
                }
            } 
            else {
                
$message->addTo($this->to);
            }
        }
        
        
// Add all CC recipients.
        
if (!empty($this->cc)) {
            if (
is_array($this->cc)) {
                foreach(
$this->cc as $address => $name) {
                    
$message->addCc($address$name);
                }
            } 
            else {
                
$message->addCc($this->cc);
            }
        }
        
        
// Add all BCC recipients.
        
if (!empty($this->bcc)) {
            if (
is_array($this->bcc)) {
                foreach(
$this->bcc as $address => $name) {
                    
$message->addBcc($address$name);
                }
            } 
            else {
                
$message->addBcc($this->bcc);
            }
        }

        
// Set REPLY TO addresses
        
if (!empty($this->replyTo)) {
            if (
is_array($this->replyTo)) {
                foreach(
$this->replyTo as $address => $name) {
                    
$message->addReplyTo($address$name);
                }
            } 
            else {
                
$message->addReplyTo($this->replyTo);
            }
        } 
        
        
// Initializing mail method object with sending parameters
        
$transport null;
        switch (
$method) {
            case 
'smtp':
                
$transport Swift_SmtpTransport::newInstance($this->smtpHost$this->smtpPort$this->smtpType);
                
$transport->setTimeout($this->smtpTimeout);
                if (!empty(
$this->smtpUsername)) {
                    
$transport->setUsername($this->smtpUsername);
                    
$transport->setPassword($this->smtpPassword);
                }
                break;
            case 
'sendmail':
                
$transport Swift_SendmailTransport::newInstance($this->sendmailCmd);
                break;
            case 
'native': default:
                
$transport Swift_MailTransport::newInstance();
                break;
        }
        
        
// Initialize Mailer
        
$mailer Swift_Mailer::newInstance($transport);
        
        
// Load plugins if any
        
if (!empty($this->__plugins)) {
            foreach(
$this->__plugins as $name => $args) {
                
$plugin_class "Swift_Plugins_{$name}";
                if (!
class_exists($plugin_class)) {
                    throw new 
Exception("SwiftMailer library does not support this plugin: {$plugin_class}");
                }
                
                
$plugin null;
                switch(
count($args)) {
                    case 
1:
                        
$plugin = new $plugin_class($args[0]);
                        break;
                    case 
2:
                        
$plugin = new $plugin_class($args[0], $args[1]);
                        break;
                    case 
3:
                        
$plugin = new $plugin_class($args[0], $args[1], $args[2]);
                        break;
                    case 
4:
                        
$plugin = new $plugin_class($args[0], $args[1], $args[2], $args[3]);
                        break;
                    default:
                        throw new 
Exception('SwiftMailer component plugin can register maximum of 4 arguments');
                }
                
$mailer->registerPlugin($plugin);
            }
        }
        
// Run Send Callback
        
$this->__runCallback($message'beforeSend');
        
        
// Attempt to send the email.
        
return $mailer->send($message$this->postErrors);
    }
    
    
/**
     * Registers a plugin supported by SwiftMailer
     * function parameters are limited to 5
     * first argument is plugin name (e.g.: if SwiftMailer plugin class is named "Swift_Plugins_AntiFloodPlugin",
     * so you should pass name like "AntiFloodPlugin")
     * All other Mixed arguments included in plugin creation call
     * 
     * @return Integer 1 on success 0 on failure
     */
    
function registerPlugin() {
        if (
func_num_args()) {
            
$args func_get_args();
            
$this->__plugins[array_shift($args)] = $args;
            return 
true;
        }
        return 
false;
    }
    
    
/**
     * Run a specific by $type callback on controller
     * who`s action is being executed. This functionality
     * is used to perform additional specific methods
     * if any is required
     * 
     * @param mixed $object - object callback being executed on
     * @param string $type - type of callback to run
     * @return void
     */
    
function __runCallback(&$object$type) {
        
$call '__'.$type.'On'.Inflector::camelize($this->__controller->action);
        if (
method_exists($this->__controller$call)) {
            
$this->__controller->{$call}($object);
        }
    }
}
?>

Step 3: preparing our controller and email templates

First we need a default layout for our emails - both for text and html. It should be located in /app/views/layouts/email/ directory. If it does not exist create it. You should have a tree similar to this:

/layouts
    /email
        /text
        /html
    /xml
    default.ctp
    ajax.ctp

Now in those /email/html/ and /email/text/ folders create a default.ctp file, which will wrap an email content. In this tutorial I will use only html template. So the layout for it can look like this:

View Template:

<!-- File: /app/views/layouts/email/html/default.ctp -->

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title><?php echo $title_for_layout;?></title>
</head>
<body>
    <?php echo $content_for_layout;?>
</body>
</html>

Now then we have a layout for an email we also need a template for a specific content of this email. We will place these specific templates in the /app/views/elements/email/ folder using same structure like in layouts. We will name our first specific template like im_excited.ctp. And the tree structure for /views/elements/ should look like:

/views
    /elements
        /email
            /html
                im_excited.ctp
            /text
        other_stuff.ctp

And the example of email element template view:

View Template:

<!-- File: /app/views/elements/email/html/im_excited.ctp -->

<p><b>Exciting isn't it?</b></p>

<p><?php echo $message?></p>

You can also use a CakePHP manual about email component then setting up email layout and templates

Example 1: Your first awesome email

Now we need to tell our controller to use this component, lets say we have employees controller and we think sending a notification later on, in this example we will send simple email through gmail smtp tls

Controller Class:

<?php // File -> app/controllers/employees_controller.php

class EmployeesController extends AppController {
    var 
$name 'Employees';
    var 
$components = array('SwiftMailer');
    
    function 
mail() {      
        
$this->SwiftMailer->smtpType 'tls';
        
$this->SwiftMailer->smtpHost 'smtp.gmail.com';
        
$this->SwiftMailer->smtpPort 465;
        
$this->SwiftMailer->smtpUsername 'my_email@gmail.com';
        
$this->SwiftMailer->smtpPassword 'hard_to_guess';

        
$this->SwiftMailer->sendAs 'html';
        
$this->SwiftMailer->from 'noone@x.com';
        
$this->SwiftMailer->fromName 'New bakery component';
        
$this->SwiftMailer->to 'my_email@gmail.com';
        
//set variables to template as usual
        
$this->set('message''My message');
        
        try {
            if(!
$this->SwiftMailer->send('im_excited''My subject')) {
                
$this->log("Error sending email");
            }
        }
        catch(
Exception $e) {
              
$this->log("Failed to send email: ".$e->getMessage());
        }
        
$this->redirect($this->referer(), nulltrue);
    }
}
?>

Example 2: Advanced Email

This example will show how to include attachments and plugins into your email. Also there are 3 callback methods added, notice that for example callback: __initializeMessageOnMail the bolded part of the callback is camel cased email sending function. If your function which sends email would be named like report_bad_employee then the callback method should look like __initializeMessageOnReportBadEmployee


Available callbacks are:
  • __initializeMessageOnMethod - executed right after the SwiftMailer message is created
  • __checkContentOnMethod - executed after a message body content is formed
  • __beforeSendOnMethod - executed right before the email is sent

Controller Class:

<?php // File -> app/controllers/employees_controller.php

class EmployeesController extends AppController {
    var 
$name 'Employees';
    var 
$components = array('SwiftMailer');

    function 
__initializeMessageOnMail(&$messageInstance) {
        
//Indicate "High" priority
        
$messageInstance->setPriority(2);
    }
    
    function 
__beforeSendOnMail(&$messageInstance) {
        
//set the bad email bounce address
        
$messageInstance->setReturnPath('bad-email-bounce-to@address.com');
    }
    
    function 
__checkContentOnMail(&$content) {
        
//strip html tags (just 4 fun :)
        //this should be used for example to check with regexp for unwanted content
        
$content strip_tags($content);
    }
    
    function 
mail() {     
        
$this->SwiftMailer->smtpType 'tls';
        
$this->SwiftMailer->smtpHost 'smtp.gmail.com';
        
$this->SwiftMailer->smtpPort 465;
        
$this->SwiftMailer->smtpUsername 'my_email@gmail.com';
        
$this->SwiftMailer->smtpPassword 'hard_to_guess';

        
$this->SwiftMailer->sendAs 'html';
        
$this->SwiftMailer->from 'noone@x.com';
        
$this->SwiftMailer->fromName 'New bakery component';
        
$this->SwiftMailer->to 'my_email@gmail.com';
        
        
//notify then receiver reads an email
        
$this->SwiftMailer->readNotifyReceipt 'my_email@gmail.com';
        
        
//some attachments
        
$this->SwiftMailer->attachments = array(
            
'C:\pictures\new.jpeg',
            
'C:\schema_net.vsd'
        
);
        
        
//add reply to
        
$this->SwiftMailer->replyTo = array('test@gmail.com''test@gg.com');
        
//register logger plugin
        
$this->SwiftMailer->registerPlugin('LoggerPlugin', new Swift_Plugins_Loggers_EchoLogger());
        
//set variables to template as usual
        
$this->set('message''My message');
        
        try {
            if(!
$this->SwiftMailer->send('im_excited''My subject')) {
                foreach(
$this->SwiftMailer->postErrors as $failed_send_to) {
                    
$this->log("Failed to send email to: $failed_send_to");
                }
            }
        }
        catch(
Exception $e) {
              
$this->log("Failed to send email: ".$e->getMessage());
        }
        
$this->autoRender false;
    }
}
?>

Example 3: Sending Email through shell

This example will show how to use this component with a shell.

First we need to create a task for our shell which will initiate this component. It should be located in app/vendors/shells/tasks/ directory, and we name file as swift_mailer.php

<?php // File -> app/vendors/shells/tasks/swift_mailer.php

App::import('Core''Controller');
App::import('Component''SwiftMailer');

class 
SwiftMailerTask extends Shell {
    
/**
     * Instance of controller to handle email views
     * 
     * @var Object
     * @access Private
     */
    
var $__controller null;
    
/**
     * Instance of SwiftMailer component
     * 
     * @var Object
     * @access Public
     */
    
var $instance null;

    
/**
     * Initializes this task
     * 
     * @access Public
     */
    
function initialize() {
        
$this->__controller = new Controller();
        
$this->instance = new SwiftMailerComponent(null);
        
$this->instance->initialize($this->__controller);
    }

    
/**
     * Pass parameter to the email view as usual
     * 
     * @param String $name - parameter name
     * @param Mixed $data - mixed parameter
     * @return void
     * @access public
     */
    
function set($name$data) {
        
$this->__controller->set($name$data);
    }
}
?>

And here is a shell which will execute a specified commands for email sending. Shell should be located in app/vendors/shells/ directory, and we name file as mailer.php

<?php // File -> app/vendors/shells/mailer.php

class MailerShell extends Shell {
    var 
$tasks = array('SwiftMailer');
    
    function 
mail() {
        
$this->out("Executing Mail command");
        
$this->SwiftMailer->instance->smtpType 'tls';
        
$this->SwiftMailer->instance->smtpHost 'smtp.gmail.com';
        
$this->SwiftMailer->instance->smtpPort 465;
        
$this->SwiftMailer->instance->smtpUsername 'my_email@gmail.com';
        
$this->SwiftMailer->instance->smtpPassword 'hard_to_guess';

        
$this->SwiftMailer->instance->sendAs 'html';
        
$this->SwiftMailer->instance->from 'my_email@gmail.com';
        
$this->SwiftMailer->instance->fromName 'TEST';
        
$this->SwiftMailer->instance->to = array(
            
'my_email@gmail.com' => 'recepient 1',
            
'receiver@bad-domain.org' => 'recepient 2'
        
);
        
        
$this->SwiftMailer->set('message''Smack my mailer shell');
        
$this->SwiftMailer->instance->registerPlugin('LoggerPlugin', new Swift_Plugins_Loggers_EchoLogger()); 
        
        try {
            if(!
$this->SwiftMailer->instance->send('im_excited''My subject')) {
                foreach(
$this->SwiftMailer->instance->postErrors as $failed_send_to) {
                    
$this->log("Failed to send email to: $failed_send_to");
                    
$this->out("Failed to send email to: $failed_send_to");
                }
            }
        }
        catch(
Exception $e) {
              
$this->log("Failed to send email: ".$e->getMessage());
              
$this->out("Failed to send email: ".$e->getMessage());
        }
        
$this->out("Finished Mail command");    
    }
}
?>

To execute a SwiftMailer shell open your command prompt or shell and go to your app directory and type cake mailer mail according to this example. If you have any questions about shell read http://book.cakephp.org/view/108/The-CakePHP-Console first


Thats it, any ideas on functionality improvements are very welcome

Report

More on Components

Advertising

Comments

  • shere1234 posted on 08/22/11 04:01:35 PM
    As I try to run this component after successfully following all the mentioned I however bumped into warning

    ): Cannot modify header information - headers already sent by (output started at D:\xampp\htdocs\gamedunzo_stable\app\controllers\components\swift_mailer.php:455) [CORE\cake\libs\controller\controller.php, line 746]
  • rajibahmed posted on 02/15/11 06:51:05 PM
    Hello,
    Firstly thank you for this awesome component. I uploaded this component with minor modification on github
    [link]http://github.com/rajibahmed/cakephp_swiftmailer4x[/link]
    I gave full credit to you.

    Best Regards
    Rajib Ahmed
  • iMatt posted on 10/20/10 05:30:02 PM
    ok i su**, so : you just echo an img tag with the $cid['key'] as src attribute.
  • iMatt posted on 10/20/10 05:28:10 PM
    Damn, sorry for flooding, I cannot edit my comment. Let's try with a code tag :

    [code]

    [end code]
  • iMatt posted on 10/20/10 05:24:53 PM
    The last part of the code went away (it was between php tags).

    So here is how you can embed your images in your e-mail view or layout :

    echo '';
    echo '';
  • iMatt posted on 10/20/10 05:20:37 PM
    Hello,

    Thanks a lot for that nice component.

    I wanted to embed an image with the swiftmailer's embed method (described here : http://swiftmailer.org/docs/embedding-files ).

    This method is the only way (that I know) to display an image automatically in outlook 2003-2007 (hopefully 2010 too) with HTML e-mails.

    Tell me if I'm wrong, but you component looks to not cover that, so here is a quick hack that works pretty well for me :

    Edit the component swift_mailer.php.

    Add a new attribute for our embed images, I've added it after the $attachments one, on line 170 :

    /**
    * List of images that should be embeded to the email.
    *
    * @var array - list of key => file paths
    * @access public
    */
    var $embedImages = array();


    Now, after the send method initialize, around line 289, add the following :

    if (!empty($this->embedImages)) {
    $keys = array();
    foreach($this->embedImages as $key => $img) {
    if (!file_exists($img)) {
    continue;
    }
    $keys[$key] = $message->embed(Swift_Image::fromPath($img));
    }
    $this->__controller->set('cid', $keys);
    }


    That's all, let me explain how it works :

    When you embed an image, your receive a cid string that reference the file. So we need to reference each image with an alias that will point to this cid.

    Here is a simple example :

    In your controller, just add your alias and images like this (this images are inside the webroot directory) :

    $this->SwiftMailer->embedImages = array('logo' => 'img/logo.png', 'bg' => 'img/bg.jpg');

    Now you can embed them in your e-mail view or layout, simply like this :




    I hope it can help someone, thanks again to the author :p
    Matt

    PS : it's my first post, and as CakePHP new user (1 month of use), I just want to thanks all contributors for that incredible framework, I just love it.
  • letimati posted on 09/21/10 10:33:45 AM
    Hi first off great article and worked first time no problems.

    I am now wondering if there is a way to use $this->set('var', $var); when sending mails from the shell?

    thanks
  • jdrummey posted on 08/11/10 05:23:07 PM
    Thanks for a great writeup! I found that my code was taking about 3 seconds to send each mail message, and suspected it was because send() function recreates the transport every time. I moved all the code for creating the transport and plugins from the send() function into a separate function in the component called init_swiftmail() that gets called once at the beginning of my controller code and returns the $mailer variable with the transport information, then the processing for each message uses a fastsend() function that takes the $mailer variable. The sending time for each message is now < 1 second, and that includes all the other processing I'm doing >
    If this would be useful to you, here are the functions to be added to swift_mailer.php in your /app/controllers/components directory:


        /** 
         * init_swiftmail()
         *
         * Initializes connection with mail server so that it can be reused
             * Code copied from the send() function
         *
         * @param String $method - email message sending method, possible values are:
         *         "smtp" - Simple Mail Transfer Protocol method
         *         "sendmail" - Sendmail method http://www.sendmail.org/
         *         "native" - Native PHP mail method
         *
         */
         
        function init_swiftmail($method = 'smtp')    {
            // Initializing mail method object with sending parameters
            $transport = null;
            switch ($method) {
                case 'smtp':
                    $transport = Swift_SmtpTransport::newInstance($this->smtpHost, $this->smtpPort, $this->smtpType);
                    $transport->setTimeout($this->smtpTimeout);
                    if (!empty($this->smtpUsername)) {
                        $transport->setUsername($this->smtpUsername);
                        $transport->setPassword($this->smtpPassword);
                    }
                    break;
                case 'sendmail':
                    $transport = Swift_SendmailTransport::newInstance($this->sendmailCmd);
                    break;
                case 'native': default:
                    $transport = Swift_MailTransport::newInstance();
                    break;
            }
            
            // Initialize Mailer
            $mailer = Swift_Mailer::newInstance($transport);


            // Load plugins if any
            if (!empty($this->__plugins)) {
                foreach($this->__plugins as $name => $args) {
                    $plugin_class = "Swift_Plugins_{$name}";
                    if (!class_exists($plugin_class)) {
                        throw new Exception("SwiftMailer library does not support this plugin: {$plugin_class}");
                    }
                    
                    $plugin = null;
                    switch(count($args)) {
                        case 1:
                            $plugin = new $plugin_class($args[0]);
                            break;
                        case 2:
                            $plugin = new $plugin_class($args[0], $args[1]);
                            break;
                        case 3:
                            $plugin = new $plugin_class($args[0], $args[1], $args[2]);
                            break;
                        case 4:
                            $plugin = new $plugin_class($args[0], $args[1], $args[2], $args[3]);
                            break;
                        default:
                            throw new Exception('SwiftMailer component plugin can register maximum of 4 arguments');
                    }
                    $mailer->registerPlugin($plugin);
                }
            }
            
            return $mailer;
        }
        
        /**
         * quicksend()
         * 
         * Copy of send() function, with the instantiation of the connection separated out 
         * into the init_swiftmail() function.
         *
         * sends Email depending on parameters specified, using
         * mail template $view and subject $subject
         * 
         * @param String $view - template for mail content
         * @param String $subject - email message subject
         * @param $mailer - mailer connection
         *
         * @return Integer - number of emails sent
         * @access Public
         */

        function fastsend($view = 'default', $subject = '', $mailer) {

            // Check if $mailer exists
            if (!$mailer) {
                throw new Exception('SwiftMailer mailer does not exist, need to start it');
            }

            // Check subject charset, asuming we are by default using "utf-8"
            if (strtolower($this->subjectCharset) != 'utf-8') {
                if (function_exists('mb_convert_encoding')) {
                    //outlook uses subject in diferent encoding, this is the case to change it
                    $subject = mb_convert_encoding($subject, $this->subjectCharset, 'utf-8');
                }
            }
            // Check if swift mailer is imported
            if (!class_exists('Swift_Message')) {
                throw new Exception('SwiftMailer was not included, check the path and filename');
            }
            
            // Create message
            $message = Swift_Message::newInstance($subject);
            
            // Run Init Callback
            $this->__runCallback($message, 'initializeMessage');
            
            $message->setCharset($this->subjectCharset);
            
            // Add html text
            if ($this->sendAs == 'both' || $this->sendAs == 'html') {
                $html_part = $this->_emailBodyPart($view, 'html');
                $message->addPart($html_part, 'text/html', $this->bodyCharset);
                unset($html_part);
            }
            
            // Add plain text or an alternative
            if ($this->sendAs == 'both' || $this->sendAs == 'text') {
                $text_part = $this->_emailBodyPart($view, 'text');
                $message->addPart($text_part, 'text/plain', $this->bodyCharset);
                unset($text_part);
            }
            
            // Add attachments if any
            if (!empty($this->attachments)) {
                foreach($this->attachments as $attachment) {
                    if (!file_exists($attachment)) {
                        continue;
                    }
                    $message->attach(Swift_Attachment::fromPath($attachment));
                }
            }
            
            // On read notification if supported
            if (!empty($this->readNotifyReceipt)) {
                $message->setReadReceiptTo($this->readNotifyReceipt);
            }
            
            $message->setMaxLineLength($this->maxLineLength);
            
            // Set the FROM address/name.
            $message->setFrom($this->from, $this->fromName);
            // Add all TO recipients.
            if (!empty($this->to)) {
                if (is_array($this->to)) {
                    foreach($this->to as $address => $name) {
                        $message->addTo($address, $name);
                    }
                } 
                else {
                    $message->addTo($this->to);
                }
            }
            
            // Add all CC recipients.
            if (!empty($this->cc)) {
                if (is_array($this->cc)) {
                    foreach($this->cc as $address => $name) {
                        $message->addCc($address, $name);
                    }
                } 
                else {
                    $message->addCc($this->cc);
                }
            }
            
            // Add all BCC recipients.
            if (!empty($this->bcc)) {
                if (is_array($this->bcc)) {
                    foreach($this->bcc as $address => $name) {
                        $message->addBcc($address, $name);
                    }
                } 
                else {
                    $message->addBcc($this->bcc);
                }
            }

            // Set REPLY TO addresses
            if (!empty($this->replyTo)) {
                if (is_array($this->replyTo)) {
                    foreach($this->replyTo as $address => $name) {
                        $message->addReplyTo($address, $name);
                    }
                } 
                else {
                    $message->addReplyTo($this->replyTo);
                }
            } 
            

            // Run Send Callback
            $this->__runCallback($message, 'beforeSend');
            
            // Attempt to send the email.
            return $mailer->send($message, $this->postErrors);
        }    
  • oberaldo posted on 08/02/10 08:17:16 PM
    Anyone try use this component with AntiFloodPlugin?
    It's works?
    because i try but without success.
    Anyone can help me, with an example? Thanks!
  • oberaldo posted on 08/02/10 08:15:12 PM
    Hi, yout tutorial and component are great.
    But i need some help, if its possible.
    Why i can send multiple emails using antiflood with yout component? Its possible you show me an example?
    Thanks a lot
    Bill
    www.cakephp.com.br
  • Akaskero posted on 07/22/10 10:38:34 AM
    I have to ask this beginner question because I have read the tutorial, ordered a book (which hasn't arrived yet from Amazon) and been on so many forums but I cannot for the life of me get cakePHP working with swiftMailer, PHPMailer or the in built cakePHP mail class.

    With this particular tutorial I have completed the following steps:

    1) Installed swift_mailer libs directory into the app/vendors/swift_mailer directory
    2) Created file: controllers/components/swift_mailer.php and additionally cut and pasted the text view code with SwiftMailerComponent class in there.
    3) Created file: controllers/employees_controller.php and pasted the text view code class EmployeesController extends AppController etc.
    4) Changed the gmail details to my very own one.

    Question:

    Now when I click the button on my form, I am taken to EmailComponent which fails. What action do I put on the form for this to work? Alternatively, what url would i browse for for this to work. CakePHP is installed the Developer way rather than in a seperate folder.

    I can download Pear mailer and get it working in less than 5 minutes as an additional page without cakePHP but this is the first framework i've tried to work with and am not doing very well at the minute.

    If anyone fancies helping out with my beginnerness to set me on the right track then I would be extremely grateful.

    Many thanks
  • nothing43953490 posted on 04/12/10 09:57:24 AM
    The spam on the bakery articles is annoying. It seems to be posted by humans, so captcha would do little. Metin's 2010-04-06 and -09 comments are/is a good example.

    How about a link rank denial and rel=nofollow filter? Maybe a flag-as-spam ajax link? The comments/flag_as_spam action could simply send an email to a moderator, or increment a field. When a comments hits 3, take the comment down. If a poster has >=2 comments taken down as spam, disable comments for their account.
  • yugi_oh posted on 04/02/10 04:56:29 AM
    I like your article and it works in windows environment. But when I upload the code into LINUX one, I face a error:

    'Failed to send email: Cannot lookup dependency "cache.disk" since it is not registered.'

    Could you please help me to fix it?
    • sky_l3ppard posted on 04/02/10 06:01:33 AM
      Its a swiftmailer library issue in first place..
      I firstly would have a look if your /tmp directory exists in root folder..
      and does it have permissions for appache to write.

      If what does not help, as far as I can tell it is cache related

      You should better post this exception on swiftmailer home site issue tracker
  • frederickd posted on 03/05/10 03:31:13 PM
    Thanks for this article! It really helped me out. First I used the examples to build an action in a controller that worked. Then I went to automate it via cron on my hosting site. Ran into a few items, but this article helped to debug my set up on Dreamhost: http://www.milesj.me/blog/read/83/Setting-Up-Cron-Jobs-With-Cake-Shells.

    One thing that I found out is that I could not use the Numbers helper in Cake in my ctp file when using the cron job. It worked as an action in the controller, but not in the cron job. So I formatted the numeric output with and it worked just fine.

    Thanks again for the article!
  • missinglink posted on 01/11/10 08:41:56 PM
    This guide helped me get SwiftMailer working with Swift-4.0.5.
    (I have also added a comment on how to get inline images working)

    http://bakery.cakephp.org/articles/view/improved-swiftmailer-component

    Peter Johnson
  • johnkeida posted on 12/07/09 11:15:55 AM
    Hi Gediminas
    THANK YOU for this component. Can you help me with a problem? How do you use sendmail function? If you can give me an example, I would appreciate it.
    John
  • t0nic posted on 10/24/09 06:49:13 PM
    for reply to:

    Component Class:

    <?php 
        
    /** 
         * reply to address
         * @var String
         * @access Public
         */
        
    var $replyTo null;


            
    //Set reply to
            
    if(!empty($this->replyTo)){
                
    //sm_com setReplyTo
                
    $message->setReplyTo($this->replyTo);
            }
    ?>

    then in controller:

    Controller Class:

    <?php 
    //just like adding from, to, etc.
    $this->SwiftMailer->replyTo $this->data['Contact']['email'];
    ?>

    Useful for contact forms that require emails: recipient hits reply to write back to commenter, not to self (or whatever server is sending the email).

    Thanks for the component btw!
  • njukks posted on 06/15/09 06:28:18 AM
    I downloaded the most recent xampp version and it worked like a charm. Thanks for the great tutorial.
  • sky_l3ppard posted on 06/10/09 04:11:34 AM
    I followed the tutorial and I get these two warnings. What could I be doing wrong?

    Warning (2): fsockopen() [function.fsockopen]: unable to connect to tls://smtp.gmail.com:465 (Unable to find the socket transport "tls" - did you forget to enable it when you configured PHP?)
    Warning (2): Cannot modify header information - headers already sent

    Confirm that You have:

    • enabled extention php_openssl in your php.ini
    • SwiftMailer->smtpType is set to tls
  • njukks posted on 06/10/09 03:57:13 AM
    I followed the tutorial and I get these two warnings. What could I be doing wrong?

    Warning (2): fsockopen() [function.fsockopen]: unable to connect to tls://smtp.gmail.com:465 (Unable to find the socket transport "tls" - did you forget to enable it when you configured PHP?)
    Warning (2): Cannot modify header information - headers already sent
  • chronon posted on 06/02/09 08:32:07 AM
    The built in cake email component is very useful in a lot of cases, but it's definitely not Swiftmail. Thanks for your efforts, your component will be useful.
  • atlet posted on 06/01/09 12:23:22 PM
    I followed the tutorial and I get an error. What's wrong?


    2009-06-01 19:14:38 Error: Failed to send email: SwiftMailer was not included, check the path and filename
    • atlet posted on 06/01/09 12:32:10 PM
      Now it's working fine. I didn't nothing.

      How can I embed picture in message?

      I followed the tutorial and I get an error. What's wrong?


      2009-06-01 19:14:38 Error: Failed to send email: SwiftMailer was not included, check the path and filename
      • sky_l3ppard posted on 06/01/09 01:50:39 PM
        Now it's working fine. I didn't nothing.

        How can I embed picture in message?

        I followed the tutorial and I get an error. What's wrong?


        2009-06-01 19:14:38 Error: Failed to send email: SwiftMailer was not included, check the path and filename

        You can embed it in your email layout or in an email template. If you fallowed example - it would be app/views/elements/email/html/im_excited.ctp and you can read more about email templates here http://book.cakephp.org/view/269/Sending-a-basic-message
        • atlet posted on 06/02/09 12:51:28 AM
          Now it's working fine. I didn't nothing.

          How can I embed picture in message?

          I followed the tutorial and I get an error. What's wrong?


          2009-06-01 19:14:38 Error: Failed to send email: SwiftMailer was not included, check the path and filename

          You can embed it in your email layout or in an email template. If you fallowed example - it would be app/views/elements/email/html/im_excited.ctp and you can read more about email templates here http://book.cakephp.org/view/269/Sending-a-basic-message

          Yes, but is there any example, how to embed image in email? I searched the swift documentation, but the example isn't suitable for this component.
          • sky_l3ppard posted on 06/02/09 04:03:33 AM
            please do not flood with comments which do not belong here. I will answer for last time with the most simple example:

            View Template:


            <!-- File: /app/views/elements/email/html/im_excited.ctp -->

            <div class="email_logo">
                <!-- This will include image from "/app/webroot/img/mail/logo.jpg" -->
                <img src="<?php echo FULL_BASE_URL.$this->webroot.'img/mail/logo.jpg';?>" alt="logo image" width="150px">
            </div>

            <p><b>Exciting isn't it?</b></p>

            <p><?php echo $message?></p>
  • r0mk1n posted on 06/01/09 03:28:57 AM
    is this possible to update your component to working from cake console?
    • sky_l3ppard posted on 06/01/09 04:45:21 AM
      is this possible to update your component to working from cake console?
      Updated.. Look at the example 3
  • josepbrines posted on 05/30/09 01:20:05 PM
    Nice work, but I'm trying it and the component can't catch any email error.
    For example, any mail adressed to qqwwee@qqwwee.com is accepted by gmail, but the domain doesn't exist.
    • sky_l3ppard posted on 05/30/09 02:03:03 PM
      Nice work, but I'm trying it and the component can't catch any email error.
      For example, any mail adressed to qqwwee@qqwwee.com is accepted by gmail, but the domain doesn't exist.
      I have changed component to version 2.2 so replace old code, and look at the example 2. In this case example 2 is logging addresses of those recipients to whom email was not sent. Notice: not all mail servers supports this. I tested with gmail and it does not return an error. for more information about swiftmailer mail sending errors here: http://swiftmailer.org/docs/failures-byreference
login to post a comment.