9.4. Sending Messages

Now that we have a message to send, let's actually get it out there. To send the message, we need to pick what kind of "transport" we're going to use, then send the message through that transport.

9.4.1. Using a Transport

Solar comes with two Solar_Mail_Transport adapters: the Phpmail one, which uses mail() internally, and an SMTP factory-adapter one, which takes a little more setup but is a lot more robust.

9.4.1.1. The PHP mail() Transport

Easy one first: the mail()-based adapter.

<?php
$mail = Solar::factory('Solar_Mail_Message');
// .. build the message ...

// build a transport and send the message
$transport = Solar::factory('Solar_Mail_Transport', array(
    'adapter' => 'Solar_Mail_Transport_Adapter_Phpmail'
));

$transport->send($mail);
?>

9.4.1.2. The Solar_Smtp Transport

The SMTP factory-adapter is a little more complicated, but still not too hard. We need to build an SMTP connection object, then tell the SMTP transport adapter to use it, then send the message.

<?php
$mail = Solar::factory('Solar_Mail_Message');
// ...

// build an SMTP connection object
$smtp = Solar::factory('Solar_Smtp', array(
    'adapter' => 'Solar_Smtp_Adapter_NoAuth',
    'host'    => 'mail.example.com',
));

// build a transport and send the message
$transport = Solar::factory('Solar_Mail_Transport', array(
    'adapter' => 'Solar_Mail_Transport_Adapter_Smtp',
    'smtp'    => $smtp,
));

$transport->send($mail);
?>

The SMTP connection object is itself a factory, and has adapters for various kinds of authentication:

9.4.2. Transport Dependency-Injection

Instead of building a transport every time you send an email, you can configure a transport for the mail message as a dependency injection. Then the mail message will be able to "send itself" using that injected transport. For Solar_Mail_Message, the config key for the transport injection is transport.

9.4.2.1. Injecting From Config Array

The easiest way of dependency injection is to pass a config array for the transport. Here's an example of injecting the PHP mail() adapter into the mail message.

<?php
// create a message object, and inject a transport config
$mail = Solar::factory('Solar_Mail_Message', array(
    'transport' => array(
        'adapter' => 'Solar_Mail_Transport_Adapter_Phpmail',
    )
));

// ... compose the message ...

// now tell the email to "send itself".
// this uses the injected transport.
$mail->send();
?>

Here's a more complex example, using the Solar_Smtp factory-adapter transport with plain authentication. Note that the transport itself uses a dependency injection for the Solar_Smtp object under the 'smtp' key.

<?php
// create a message object, and inject a transport config
$mail = Solar::factory('Solar_Mail_Message', array(
    'transport' => array(
        'adapter' => 'Solar_Mail_Transport_Adapter_Smtp',
        'smtp' => array(
            'adapter'  => 'Solar_Smtp_Adapter_PlainAuth',
            'username' => 'pmjones',
            'password' => 'secret',
            'host'     => 'mail.example.com',
        ),
    )
));

// ... compose the message ...

// now tell the email to "send itself".
// this uses the injected transport.
$mail->send();
?>

This is quite convenient, especially since you can set up those arrays in your config file in advance, making them the default configs each time you create a Solar_Mail_Message object. In that case, you can use the class names instead of the full configuration arrays.

<?php
$config['Solar_Mail_Message'] = array(
    'transport' => 'Solar_Mail_Transport_Adapter_Smtp',
);

$config['Solar_Mail_Transport_Adapter_Smtp'] = array(
    'transport' => 'Solar_Smtp_Adapter_PlainAuth',
);

$config['Solar_Smtp_Adapter_PlainAuth'] = array(
    'adapter'  => 'Solar_Smtp_Adapter_PlainAuth',
    'username' => 'pmjones',
    'password' => 'secret',
    'host'     => 'mail.example.com',
);
?>

Using the config-file-centered process instead of the logic-centered process means that you can have all your settings in one place for use throughout your application. You can even change adapters from the config file without changing any of the mail-sending code, as long as you keep the same registry names.

9.4.2.2. Injecting From the Registry

The only problem with injection using a config array is that the dependency objects get created anew each time you create a Solar_Mail_Message. Sometimes it's better to use registry objects for the dependency, so you don't use up resources re-creating identical objects over and over again.

You can register the transport and SMTP objects in your bootstrap file or Solar_Controller_Page::_setup() so they are available throughout the application:

<?php
// build a Solar_Smtp object
$smtp = Solar::factory('Solar_Smtp', array(
    'adapter'  => 'Solar_Smtp_Adapter_PlainAuth',
    'username' => 'pmjones',
    'password' => 'secret',
    'host'     => 'mail.example.com',
));

// register it as 'smtp'
Solar_Registry::set('smtp', $smtp);

// build a Solar_Mail_Transport object with the SMTP object injected
$transport = Solar::factory('Solar_Mail_Transport', array(
    'adapter' => 'Solar_Mail_Transport_Adapter_Smtp',
    'smtp'    => 'smtp', // uses the registered 'smtp' object
);

// register the transport as 'mail-transport'
Solar_Registry::set('mail-transport', $transport);
?>

Now when you create a new mail message, you can tell it that there's a transport already available, and call send() directly on the message.

<?php
$mail = Solar::factory('Solar_Mail_Message', array(
    'transport' => 'mail-transport',
));

// ... build the message, and then:
$mail->send();
?>

If you want to, you can put it all of this config information in the Solar config file. Then you can lazy-load the objects from the registry, and they will automatically have all the right settings. The various dependency objects will be lazy-loaded automatically for you.

In your Solar.config.php file:

<?php
// configure SMTP
$config['Solar_Smtp'] = array(
    'adapter'  => 'Solar_Smtp_Adapter_PlainAuth',
    'username' => 'pmjones',
    'password' => 'secret',
    'host'     => 'mail.example.com',
);

// configure mail transport
$config['Solar_Mail_Transport'] = array(
    'adapter' => 'Solar_Mail_Transport_Adapter_Smtp',
    'smtp'    => 'smtp',
);

// tell all mail messages to use the registered 'mail-transport'
$config['Solar_Mail_Message']['transport'] = 'mail-transport';
?>

Then all you have to do in your setup logic is register class names instead of objects ...

<?php
Solar_Registry::set('smtp', 'Solar_Smtp');
Solar_Registry::set('mail-transport', 'Solar_Mail_Transport');
?>

... which will cause those objects to be created only at the moment they are first called as depndencies, and the same object will be reused every time you pull it from the registry.

Now you can send an email message very simply:

<?php
// create and build a message
$mail = Solar::factory('Solar_Mail_Message');
// ...

// send the message; this creates the SMTP and mail-transport objects
// from the config-file settings, and sends the message trough the
// registered transport.
$mail->send();
?>


Local