3 * File containing the ezcMail class
7 * @copyright Copyright (C) 2005-2009 eZ Systems AS. All rights reserved.
8 * @license http://ez.no/licenses/new_bsd New BSD License
12 * The main mail class.
14 * You can use ezcMail together with the other classes derived from ezcMailPart
15 * to build email messages. When the mail is built, use the Transport classes
18 * This example builds and sends a simple text mail message:
20 * $mail = new ezcMail;
21 * $mail->from = new ezcMailAddress( 'sender@example.com', 'Adrian Ripburger' );
22 * $mail->addTo( new ezcMailAddress( 'receiver@example.com', 'Maureen Corley' ) );
23 * $mail->subject = "Hi";
24 * $mail->body = new ezcMailText( "I just mail to say I love you!" );
25 * $transport = new ezcMailMtaTransport();
26 * $transport->send( $mail );
29 * You can also derive your own mail classes from this class if you have
30 * special requirements. An example of this is the ezcMailComposer class which
31 * is a convenience class to send simple mail structures and HTML mail.
33 * There are several headers you can set on the mail object to achieve various
35 * - Reply-To - Set this to an email address if you want people to reply to an
36 * address other than the from address.
37 * - Errors-To - If the mail can not be delivered the error message will be
38 * sent to this address.
40 * @property ezcMailAddress $from Contains the from address as an
41 * ezcMailAddress object.
42 * @property array(ezcMailAddress) $to Contains an array of ezcMailAddress objects.
43 * @property array(ezcMailAddress) $cc Contains an array of ezcMailAddress objects.
44 * @property array(ezcMailAddress) $bcc Contains an array of ezcMailAddress objects.
45 * @property string $subject
46 * Contains the subject of the e-mail.
47 * Use setSubject if you require a
49 * @property string $subjectCharset
50 * The encoding of the subject.
51 * @property ezcMailPart $body The body part of the message.
53 * @property-read string $messageId
54 * The message ID of the message. Treat
55 * as read-only unless you're 100% sure
56 * what you're doing. Also accessible through
57 * the deprecated property messageID.
58 * @property-read integer $timestamp
59 * The date/time of when the message was
60 * sent as Unix Timestamp.
61 * @property ezcMailAddress $returnPath Contains the Return-Path address as an
62 * ezcMailAddress object.
64 * @apichange Remove the support for the deprecated property messageID.
70 class ezcMail
extends ezcMailPart
75 const SEVEN_BIT
= "7bit";
80 const EIGHT_BIT
= "8bit";
85 const BINARY
= "binary";
88 * Quoted printable encoding.
90 const QUOTED_PRINTABLE
= "quoted-printable";
95 const BASE64
= "base64";
98 * Constructs an empty ezcMail object.
100 public function __construct()
102 parent
::__construct();
104 $this->properties
['from'] = null;
105 $this->properties
['to'] = array();
106 $this->properties
['cc'] = array();
107 $this->properties
['bcc'] = array();
108 $this->properties
['subject'] = null;
109 $this->properties
['subjectCharset'] = 'us-ascii';
110 $this->properties
['body'] = null;
111 $this->properties
['messageId'] = null;
112 $this->properties
['returnPath'] = null;
116 * Sets the property $name to $value.
118 * @throws ezcBasePropertyNotFoundException
119 * if the property does not exist.
120 * @throws ezcBasePropertyPermissionException
121 * if the property is read-only.
122 * @param string $name
123 * @param mixed $value
126 public function __set( $name, $value )
132 if ( $value !== null && !$value instanceof ezcMailAddress
)
134 throw new ezcBaseValueException( $name, $value, 'ezcMailAddress or null' );
136 $this->properties
[$name] = $value;
142 if ( !is_array( $value ) )
144 throw new ezcBaseValueException( $name, $value, 'array( ezcMailAddress )' );
146 foreach ( $value as $key => $obj )
148 if ( !$obj instanceof ezcMailAddress
)
150 throw new ezcBaseValueException( "{$name}[{$key}]", $obj, 'ezcMailAddress' );
153 $this->properties
[$name] = $value;
157 $this->properties
['subject'] = trim( $value );
160 case 'subjectCharset':
161 $this->properties
['subjectCharset'] = $value;
165 if ( !$value instanceof ezcMailPart
)
167 throw new ezcBaseValueException( $name, $value, 'ezcMailPart' );
169 $this->properties
['body'] = $value;
174 $this->properties
['messageId'] = $value;
178 throw new ezcBasePropertyPermissionException( $name, ezcBasePropertyPermissionException
::READ
);
182 parent
::__set( $name, $value );
188 * Returns the property $name.
190 * @throws ezcBasePropertyNotFoundException
191 * if the property does not exist.
192 * @param string $name
196 public function __get( $name )
203 return (array) $this->properties
[$name];
207 case 'subjectCharset':
211 return $this->properties
[$name];
213 case 'messageID': // deprecated version
214 return $this->properties
['messageId'];
217 return strtotime( $this->getHeader( "Date" ) );
220 return parent
::__get( $name );
225 * Returns true if the property $name is set, otherwise false.
227 * @param string $name
231 public function __isset( $name )
240 case 'subjectCharset':
244 return isset( $this->properties
[$name] );
246 case 'messageID': // deprecated version
247 return isset( $this->properties
['messageId'] );
250 return $this->getHeader( "Date" ) != null;
253 return parent
::__isset( $name );
258 * Adds the ezcMailAddress $address to the list of 'to' recipients.
260 * @param ezcMailAddress $address
262 public function addTo( ezcMailAddress
$address )
264 $this->properties
['to'][] = $address;
268 * Adds the ezcMailAddress $address to the list of 'cc' recipients.
270 * @param ezcMailAddress $address
272 public function addCc( ezcMailAddress
$address )
274 $this->properties
['cc'][] = $address;
278 * Adds the ezcMailAddress $address to the list of 'bcc' recipients.
280 * @param ezcMailAddress $address
282 public function addBcc( ezcMailAddress
$address )
284 $this->properties
['bcc'][] = $address;
288 * Returns the generated body part of this mail.
290 * Returns an empty string if no body has been set.
294 public function generateBody()
296 if ( is_subclass_of( $this->body
, 'ezcMailPart' ) )
298 return $this->body
->generateBody();
304 * Returns the generated headers for the mail.
306 * This method is called automatically when the mail message is built.
307 * You can re-implement this method in subclasses if you wish to set
308 * different mail headers than ezcMail.
312 public function generateHeaders()
314 // set our headers first.
315 if ( $this->from
!== null )
317 $this->setHeader( "From", ezcMailTools
::composeEmailAddress( $this->from
) );
320 if ( $this->to
!== null )
322 $this->setHeader( "To", ezcMailTools
::composeEmailAddresses( $this->to
) );
324 if ( count( $this->cc
) )
326 $this->setHeader( "Cc", ezcMailTools
::composeEmailAddresses( $this->cc
) );
328 if ( count( $this->bcc
) )
330 $this->setHeader( "Bcc", ezcMailTools
::composeEmailAddresses( $this->bcc
) );
333 $this->setHeader( 'Subject', $this->subject
, $this->subjectCharset
);
335 $this->setHeader( 'MIME-Version', '1.0' );
336 $this->setHeader( 'User-Agent', 'eZ Components' );
337 $this->setHeader( 'Date', date( 'r' ) );
338 $idhost = $this->from
!= null && $this->from
->email
!= '' ?
$this->from
->email
: 'localhost';
339 if ( is_null( $this->messageId
) )
341 $this->setHeader( 'Message-Id', '<' . ezcMailTools
::generateMessageId( $idhost ) . '>' );
345 $this->setHeader( 'Message-Id', $this->messageID
);
348 // if we have a body part, include the headers of the body
349 if ( is_subclass_of( $this->body
, "ezcMailPart" ) )
351 return parent
::generateHeaders() . $this->body
->generateHeaders();
353 return parent
::generateHeaders();
357 * Returns an array of mail parts from the current mail.
359 * The array returned contains objects of classes:
362 * - ezcMailRfc822Digest
363 * If the method is called with $includeDigests as true, then the returned
364 * array will not contain ezcMailRfc822Digest objects, but instead the mail
365 * parts inside the digests.
366 * The parameter $filter can be used to restrict the returned mail parts,
367 * eg. $filter = array( 'ezcMailFile' ) to return only file mail parts.
369 * A typical use for this function is to get a list of attachments from a mail.
372 * // $mail is an ezcMail object
373 * $parts = $mail->fetchParts();
374 * // after the above line is executed, $parts will contain an array of mail parts objects,
375 * // for example one ezcMailText object ($parts[0]) and two ezcMailRfc822Digest objects ($parts[1] and $parts[2]).
376 * // the ezcMailText object will be used to render the mail text, and the
377 * // other two objects will be displayed as links ("view attachment")
379 * // when user clicks on one of the two attachments, the parts of that attachment
380 * // must be retrieved in order to render the attached digest:
381 * $subparts = $parts[1]->mail->fetchParts();
382 * // after the above line is executed, $subparts will contain an array of mail parts objects,
383 * // for example one ezcMailText object and one ezcMailFile object
386 * @param array(string) $filter
387 * @param bool $includeDigests
388 * @return array(ezcMailPart)
390 public function fetchParts( $filter = null, $includeDigests = false )
392 $context = new ezcMailPartWalkContext( array( __CLASS__
, 'collectPart' ) );
393 $context->includeDigests
= $includeDigests;
394 $context->filter
= $filter;
396 $this->walkParts( $context, $this );
397 return $context->getParts();
401 * Walks recursively through the mail parts in the specified mail object.
403 * $context is an object of class ezcMailPartWalkContext, which must contain
404 * a valid callback function name to be applied to all mail parts. You can use
405 * the collectPart() method, or create your own callback function which can
406 * for example save the mail parts to disk or to a database.
408 * For the properties you can set to the walk context see: {@link ezcMailPartWalkContext}
414 * public static function saveMailPart( $context, $mailPart )
416 * // code to save the $mailPart object to disk
420 * // use the saveMailPart() function as a callback in walkParts()
421 * // where $mail is an ezcMail object.
422 * $context = new ezcMailPartWalkContext( array( 'App', 'saveMailPart' ) );
423 * $context->includeDigests = true; // if you want to go through the digests in the mail
424 * $mail->walkParts( $context, $mail );
427 * @param ezcMailPartWalkContext $context
428 * @param ezcMailPart $mail
430 public function walkParts( ezcMailPartWalkContext
$context, ezcMailPart
$mail )
432 $className = get_class( $mail );
434 switch ( $className )
437 case 'ezcMailComposer':
438 if ( $mail->body
!== null )
440 $this->walkParts( $context, $mail->body
);
444 case 'ezcMailMultipartMixed':
445 case 'ezcMailMultipartAlternative':
446 case 'ezcMailMultipartDigest':
447 case 'ezcMailMultipartReport':
448 foreach ( $mail->getParts() as $part )
450 $this->walkParts( $context, $part );
454 case 'ezcMailMultipartRelated':
455 $this->walkParts( $context, $mail->getMainPart() );
456 foreach ( $mail->getRelatedParts() as $part )
458 $this->walkParts( $context, $part );
462 case 'ezcMailRfc822Digest':
463 if ( $context->includeDigests
)
465 $this->walkParts( $context, $mail->mail
);
467 elseif ( empty( $context->filter
) ||
in_array( $className, $context->filter
) )
469 call_user_func( $context->callbackFunction
, $context, $mail );
475 case 'ezcMailDeliveryStatus':
476 if ( empty( $context->filter
) ||
in_array( $className, $context->filter
) )
478 call_user_func( $context->callbackFunction
, $context, $mail );
483 // for cases where a custom mail class has been specified with $parser->options->mailClass
484 if ( in_array( 'ezcMail', class_parents( $className ) ) )
486 if ( $mail->body
!== null )
488 $this->walkParts( $context, $mail->body
);
492 // for cases where a custom file class has been specified with $parser->options->fileClass
493 if ( in_array( 'ezcMailFile', class_parents( $className ) ) )
495 if ( empty( $context->filter
) ||
in_array( $className, $context->filter
) )
497 call_user_func( $context->callbackFunction
, $context, $mail );
505 * Saves $mail in the $context object.
507 * This function is used as a callback in the fetchParts() method.
509 * @param ezcMailPartWalkContext $context
510 * @param ezcMailPart $mail
512 protected static function collectPart( ezcMailPartWalkContext
$context, ezcMailPart
$mail )
514 $context->appendPart( $mail );