
The fEmail class provides an interface to very easily send well-formed emails with UTF-8 content, HTML, attachments and S/MIME encryption and signing. fEmail uses PHPs built-in mail()
function by default, but can be used with fSMTP for mass emailing or mailing via a remote mail server.
Creating a new email is as simple as making a new instance of fEmail:
$email = new fEmail();
fEmail supports To:
, CC:
and BCC:
recipients through the methods addRecipient()
, addCCRecipient()
and addBCCRecipient()
. Each method requires a single parameter $email
and accepts a second optional parameter $name
. The add methods can be called any number of times to add any number of recipients:
// Add our recipient
$email->addRecipient('will@example.com', 'Will');
// Add a few people to the CC and BCC lists
$email->addCCRecipient('john@example.com');
$email->addCCRecipient('bob@example.com', 'Bob Smith, Jr.');
$email->addBCCRecipient('alice@example.com');
If need be, all regular, CC and BCC recipients can be cleared by calling the method clearRecipients()
.
$email->clearRecipients();
When sending a message you will also need to set the From:
address via the method setFromEmail()
. The first parameter, $email
, is required, however the second parameter, $name
, is optional. Unfortunately the implementation of mail()
on Windows does not allow setting the $name
parameter. A $name
will work on Windows if you use fSMTP.
// Set who the email is from
$email->setFromEmail('will@example.com');
// Include the users name
$email->setFromEmail('will@example.com', 'Will');
It is also possible to set the Return-Path:
header on almost all servers. This email address is listed as the true source of the email and will be the recipient of any bounces or delivery notifications. The method setBounceToEmail()
sets this address with just a single parameter $email
:
$email->setBounceToEmail('will@example.com');
All email must have a subject and body set by the methods setSubject()
and setBody()
. Both of these methods accept a single parameter, a UTF-8 string.
// Set the subject include UTF-8 curly quotes
$email->setSubject('This wont break email programs because it is properly encoded by the class');
// Set the body to include a string containing UTF-8
$email->setBody('This is the body of the email');
The setBody()
method can also take a second parameter, $unindent_expand_constants
, which is a boolean. When this parameter is TRUE
, the body will be unindented as much as possible, and will have all {CONSTANT_NAME}
strings replaced with the constants value, if defined. This parameter is useful for inline generation of bodies where you dont want to deal with the issues of having a fully unindented end to a HEREDOC
string.
For example, the following PHP:
// Unindenting the body and exapanding curly-braced constant names
if ($email_address) {
$email = new fEmail();
$email->addRecipient($email_address);
//
$email->setBody("
Hello $name,
Thanks for submitting your request, well get back to you as soon as we can!
{EMAIL_SIGNATURE}
", TRUE);
}
would create the email body:
Hello John Smith,
Thanks for submitting your request, well get back to you as soon as we can!
Sincerely,
The ACME Co. Team
Without the parameter, the body would be:
Hello John Smith,
Thanks for submitting your request, well get back to you as soon as we can!
{EMAIL_SIGNATURE}
The HEREDOC
equivalent of our desired output would be:
if ($email_address) {
$email = new fEmail();
//
$signature = EMAIL_SIGNATURE;
$email->setBody(<<<EOF
Hello $name,
Thanks for submitting your request, well get back to you as soon as we can!
$signature
EOF
, TRUE);
}
In short, the $unindent_expand_constants
parameter allows for cleaner PHP with logical indentation levels.
When dealing with a more complex body example, or wishing to separate the email templates from your PHP, the method loadBody()
can be used. This methods accepts two parameters, the $file
to load the body from and an array of $replacements
to be performed.
The $file
parameter can be either a file path or an fFile object. The $replacements
parameter should be an associative array with the terms to search for being the keys and the strings to replace them with being the values.
$email->loadBody(
'./email_templates/welcome.txt',
array(
'{NAME}' => $name,
'{LOGIN}' => $login
)
);
Please note that the terms to search for do not have to be in any particular format, a simple str_replace()
call is used to do the replacements.
It is also possible to add an HTML version of the body by passing it to setHTMLBody()
. This HTML content should be encoded using UTF-8:
$email->setHTMLBody('<p>This it the HTML version of the body</p>');
Just like loadBody()
for the plaintext body, the HTML body can be loaded from a file via loadHTMLBody()
. This methods accepts two parameters, the $file
to load the body from and an array of $replacements
to be performed.
The $file
parameter can be either a file path or an fFile object. The $replacements
parameter should be an associative array with the terms to search for being the keys and the strings to replace them with being the values.
$email->loadHTMLBody(
'./email_templates/welcome.html',
array(
'{NAME}' => $name,
'{LOGIN}' => $login
)
);
Please note that the terms to search for do not have to be in any particular format, a simple str_replace()
call is used to do the replacements.
When using an HTML body, it is possible to add files to the email that can be referenced in the HTML, but do not appear as an attachment. Such related files are added by the addRelatedFile()
method. This method requires either one or two parameters: $contents
, or $contents
and $filename
. If $contents
is an fFile object, no $filename
is necessary. A URL will be returned for direct embedding into HTML src
or href
attributes.
$logo_url = $email->addRelatedFile(new fFile('./images/logo.gif'));
$email->setHTMLBody("<p>Thanks for your input!</p><p>ACME Corp.<img src='$logo_url' alt='ACME Corp'></p>");
There is an optional third parameter, $mime_type
, which can be used to fix incorrect detection of the mime type of a related file.
$logo_url = $email->addRelatedFile(new fFile('./images/logo.gif'), 'email_logo.gif', 'image/gif');
Attachments can be added to an email by calling the method addAttachment()
. The method requires either one or two parameters: $contents
, or $contents
and $filename
. If $contents
is an fFile object, no $filename
is necessary.
foreach ($result as $row) {
$csv_contents .= join(",", $row) . "\n";
}
// Pass in the contents of the file, plus a filename for it
$email->addAttachment($csv_contents, 'report.csv');
// Passing an fFile object
$email->addAttachment(new fFile('./report.pdf'));
There is an optional third parameter, $mime_type
, which can be used to fix incorrect detection of the mime type of an attachment.
$email->addAttachment($file_contents, 'filename.tab', 'text/csv');
There is no limit to the number of attachments.
The fEmail class provides support for encrypting and signing messages using S/MIME. To encrypt a message, the PEM-encoded public certificate will be needed. To sign a message, the PEM-encoded private key will be needed. To encrypt and sign you will need both (but not for the user). Please see Obtaining a Secure Certificate/Key Pair for information about how to get the necessary files.
To encrypt a message, call the method encrypt()
and pass the path to the recipients PEM-encoded public certificate:
$email->encrypt('/path/to/recipients.cer');
To sign a message, call sign()
and pass in the senders public certificate path, private key path and private key password (if applicable):
$email->sign('/path/to/senders.cer', '/path/to/senders.key', 'key_password');
If you call both sign()
and encrypt()
(in either order), the message will be signed, then encrypted and then signed again. This is the most secure method, however certain older email clients may not open such emails.
To send an email, simply call the send()
method.
$message_id = $email->send();
The return value is the generated Message-ID
header for the email, which can be used with the In-Reply-To
header for tracking replies. The fMailbox class provides functionality for checking and parsing email.
If there is a need to add custom headers to an email message, the method addCustomHeader()
will accept the header $name
and $value
. The $value
should be a plain string - the method will handle any necessary encoding or line wrapping necessary to keep the headers standards-compliant.
$email->addCustomHeader('X-My-Header', 'This is the value I want to send!');
It is possible to set multiple headers at once by passing an associative array to addCustomHeader()
.
// Set headers that some programs use to indicate priority
$email->addCustomHeader(array(
'X-Priority' => '1',
'Importance' => 'High'
));
On some linux/unix server running qmail as the sendmail replacement, you may experience issues with emails looking corrupted to the recipients. This will often take the form of equal signs (=) appearing throughout the content and lines being wrapped in odd places.
The technical cause of the issue is that the qmail sendmail binary is automatically replacing every line feed (\n) with a CR-LF (\r\n) because the email specifications require emails use CR-LF and linux uses LF as the line ending. Qmail is trying to ensure you are sending emails that meet specifications, however it is not checking to see if the email already has the proper line endings.
The first way to try and solve this issue is to use fSMTP and connect to the SMTP server on localhost
. This by-passes the command-line interface to qmail:
$smtp = new fSMTP('localhost');
$email->send($smtp);
If that is not possible, the static method fixQmail()
should fix the issue. On servers where open_basedir
and safe_mode
are not in effect, fEmail will make a commandline call to sendmail and will replace all CR-LF with just LF. If that is not possible, fEmail will simply replace all CR-LFs with LF, however emails with long headers may still have issues.
Normally you would only enable this fix if you experience the issue. Since the fix affects all instances of fEmail, youll normally want to call it in a configuration file.
fEmail::fixQmail();
In certain situations it may be necessary to validate an email address when not using fValidation or fORMValidation with the ORM. The fEmail class provides two regular expression constants to help with the task.
These regular expressions are designed to fully match the mailbox
specification of RFC2822 Section 3.4 except for allowing comments and folding white space. Quoted strings are supported along with the +
, -
and other special characters.
Below is an example of some of the various valid email address formats that are supported:
# regular address
will@example.com
# with + suffix
will+foo@example.com
# with - suffix
will-foo@example.com
# periods
will.foo@example.com
# quoted strings
"will foo"@example.com
# combinations
"will foo".bar+baz@example.com
The two constants are EMAIL_REGEX
and NAME_EMAIL_REGEX
. EMAIL_REGEX
will match an email address, while NAME_EMAIL_REGEX
will match a name <email>
string.
EMAIL_REGEX
captures 3 subpatterns in the following format:
For example:
preg_match(fEmail::EMAIL_REGEX, 'will@example.com', $matches);
echo $matches[0] . "\n";
echo $matches[1] . "\n";
echo $matches[2];
will output the following:
will@example.com
will
example.com
NAME EMAIL_REGEX
captures 5 subpatterns in the following format:
For example:
preg_match(fEmail::NAME_EMAIL_REGEX, 'Will <will@example.com>', $matches);
echo $matches[0] . "\n";
echo $matches[1] . "\n";
echo $matches[2] . "\n";
echo $matches[3] . "\n";
echo $matches[4];
will output the following:
Will <will@example.com>
Will
will@example.com
will
example.com