# Proposal: Mail Handling, feedback requested

- Thread: https://externals.io/message/73400
- Original archive: https://news-web.php.net/php.internals/73400
- Started by Gary Mort on 2014-03-24T16:14:57+00:00
- Messages: 1
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #73400 — Gary Mort — 2014-03-24T16:14:57+00:00

URL: https://externals.io/message/73400#73400

Current e-mail handling in PHP is dreadful.   Almost every framework 
implements it's own email handling class in order to make sending e-mail 
reliable, easy to configure, and to implement multiple mail schemes.


This means for developers working on multiple frameworks, they can't 
just call mail($recipient, $subject, $message) - they have to perform 
convoluted checking to find out what framework they are using, and then 
use the appropriate api.

That was understandable in PHP v4 and in v5 - 5.2.

Today though it is a waste of time, PHP internally has implemented a 
smart, extensible system for generalizing access to system oriented 
structures.  Handlers/Wrappers.

By subclassing the appropriate handler class, a PHP application can 
implement specific functionality to handle specific elements of Session 
and Stream processing, without having to implement every one of them and 
without requiring specialized PHP classes to be used directly.

http://www.php.net/manual/en/function.session-set-save-handler.php
http://www.php.net/manual/en/function.stream-wrapper-register.php
http://www.php.net/manual/en/class.sessionhandler.php
http://www.php.net/manual/en/class.streamwrapper.php


My proposal[which I am willing to work on coding] is to replace the 
current `mail()` function with one that will support handlers.

Note: This is only to handle HALF of the issues that we deal with when 
sending e-mail: sending the actual message.  It does not attempt to 
address creating/formatting e-mail messages except in a very general 
since.  My proposed class would be:


class MailMessage {

/* Properties */
$private array $recipients;
$private string $sender;
$private string $subject;
$private string $body;
$private string $header;
$private string $additionalParamters;
$private array $sentTo;

// Mail handler used to send mail, if none specified the current default 
handler is used
$private MailHandler $handler;

/* Primary Methods */


/* create a new mail message, constructor parameters mimic current
 `mail()` function parameters.  Throws exception if there is a problem.
It is perfectly valid to create a message and not specify any of the
parameters - it is only when the message is SENT that the parameters
must be valid */

public MailMessage __construct (  [string $to, string $subject, string 
$message, string $additional_headers, string $additional_parameters, 
string $from, MailHandlerInterface $handler] )

/* Send a mail message.  Throws exception on problems.  If $handler is
specified, then that handler is used.  If not specified, then the the
objects $handler property is used.  */
public MailMessage send ([MailHandle $handler ]);


/* Utility Methods */

/* Sets appropriate private properties, checks parameters and
throwsexceptions when not properly formatted */
public MailMessage setRecipients ( array $recipients )

public MailMessage setSender ( string $sender );

public MailMessage setSubject ( string $$subject );

public MailMessage setBody ( string $body );

public MailMessage setHeader ( string $header );

public MailMessage setAdditionalParameters ( string $additionalParameters );

public MailMessage setHandler( MailHandlerInterface $handler );

public MailMessage setSentTo();

/* Magic method to allow direct setting of sender, subject, body,
recipients, and additionalParameters.   It is not recommended to
allow the setting of mail handler or sentTo in this manner. */

public MailMessage __set();

/* Gets appropriate private properties and returns them
either as strings or as arrays */
public mixed getRecipients([string $format = 'string']);

public mixed getSubject([string $format = 'string']);

public mixed getBody([string $format = 'string']);

public mixed getHeader([string $format = 'string']);

public mixed getAdditionalParameters([string $format = 'string']);

public MailHandlerInterface getHandler();

public array getSentTo();

/* Magic get method  for sender, subject, body, recipients,
and additionalParameters.   It is not recommended to allow retrieval
of the mail handler in this manner. Always returns data as an
associative array. */
public array __get();

}

Sending e-mail in an object oriented manner can be as simple as:
$message = new MailMessage($to, $subject, $message);
$message->send;

Or simply continue to use mail($to, $subject, $message) and it will 
handle the above transparently.


In addition to a MailMessage class, there would also be a MailHandler 
interface.  It only requires 2 methods, send and sendBatch.

MailHandlerInterface {
/* Methods */
abstract public bool send ( MailMessage $message [, string $address ] )
abstract public bool sendBatch ( MailMessage $message [, array 
$recipients ] )
}


sendBatch at it's simplest would simply loop through each recipient in 
the message and call send($message, $recipient).   It could also be 
called to send mail only to specific recipients.  Handlers are free to 
use other logic, for example if using Postfix's maildrop function, the 
message can be saved as a file to a specific directory and Postfix 
monitors the directory and send's e-mail from it: no need to make costly 
network connections for every recipient.

send is used to deliver a message to a single recipient.  If a message 
has multiple potential recipients, send should throw an exception if the 
specific recipient is not specified via $address.

The send and sendBatch function CAN be used to send a message to an 
address that is not listed as a recipient.  IE this method can be used 
for transparently copying others for every message the handler sends out.

Both send and sendBatch must update the sentTo property of the message 
to add each recipient a message is actually sent to.  This allows mass 
e-mail situations to add tracking information to embedded images in the 
message for each recipient.  Note, such functionality is beyond the 
scope of the base interface.

Both send and sendBatch MAY check the sentTo property and avoid sending 
duplicate copies of a message but this is NOT required.

Lastly, this would require an additional function:
bool mail_handler_register ( MailHandlerInterface $handler [, int $flags 
= 0 ] )


My goal is that the creation and sending of basic e-mail should be a 
simple operation.  It should be possible for a developer to simply call 
the `mail()` function and not be concerned about possible e-mail handling 
configurations.

At the same time, Application Designers and Framework designers should 
be able to augment basic e-mail delivery with their own custom handling 
rules.   Adding the above functionality to PHP would allow for easy 
migration - in most cases all they would have to do is add the send and 
sendBatch methods to their current mail class and make sure to flag the 
class as implementing the MailHandlerInterface.   Then it can be 
registered to deal with sending or not.


Possible additions to the above would be:
A MailHandlerClass which can be extended.  This way a handler that only 
wanted to customize the send or sendBatch method could simply inherit 
the base methods and customize.

Adding a createMessage method to the MailHandlerInterface so that the 
message object that is created by mail($to, $subject, $message) can 
include custom functionality.

Adding a mail_create() function which would return a MailMessage object 
using the createMessage method from the currently registered 
MailHandlerInterface.



Feedback on changes to the classes to bring things in line with current 
standards is appreciated.  In addition, pointers to the files which 
currently implement the handler functionality in PHP would be 
appreciated.   I believe I found the functionality, but as I read the 
code it seems that SessionHandlers and StreamHandlers do not inherit any 
common code, ie each one is coded individually - so if there is a 
generic mechanism for registering/using handlers already in the code I 
am missing I'd rather extend that then write new code. :-)


-Gary
