Open-Source PHP Framework - Designed for rapid development of performance-oriented scalable applications

/packages/amazon-ses

[return to app]
1 <?php
2
/**
3 * This file is packaged as part of the Amazon Simple Email Service (Amazon SES) Vork App
4 * for use with the Vork Enterprise Framework www.Vork.us
5 *
6 * Copyright (c) 2011, Dan Myers.
7 * Parts copyright (c) 2008, Donovan Schonknecht.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 *   this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright
16 *   notice, this list of conditions and the following disclaimer in the
17 *   documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * This is a modified BSD license (the third clause has been removed).
32 * The BSD license may be found here:
33 * http://www.opensource.org/licenses/bsd-license.php
34 *
35 * Amazon Simple Email Service is a trademark of Amazon.com, Inc. or its affiliates.
36 *
37 * SimpleEmailService is based on Donovan Schonknecht's Amazon S3 PHP class, found here:
38 * http://undesigned.org.za/2007/10/22/amazon-s3-php-class
39 */
40
41 /**
42 * Amazon SimpleEmailService PHP class
43 *
44 * @link http://sourceforge.net/projects/php-aws-ses/
45 * version 0.8.2
46 *
47 */
48
class SimpleEmailService {
49     protected 
$__accessKey// AWS Access key
50     
protected $__secretKey// AWS Secret key
51     
protected $__host;
52
53     public function 
getAccessKey() { return $this->__accessKey; }
54     public function 
getSecretKey() { return $this->__secretKey; }
55     public function 
getHost() { return $this->__host; }
56
57     protected 
$__verifyHost 1;
58     protected 
$__verifyPeer 1;
59
60     
// verifyHost and verifyPeer determine whether curl verifies ssl certificates.
61     // It may be necessary to disable these checks on certain systems.
62     // These only have an effect if SSL is enabled.
63     
public function verifyHost() { return $this->__verifyHost; }
64     public function 
enableVerifyHost($enable true) { $this->__verifyHost $enable; }
65
66     public function 
verifyPeer() { return $this->__verifyPeer; }
67     public function 
enableVerifyPeer($enable true) { $this->__verifyPeer $enable; }
68
69     
/**
70     * Constructor
71     *
72     * @param string $accessKey Access key
73     * @param string $secretKey Secret key
74     * @return void
75     */
76     
public function __construct($accessKey null$secretKey null$host 'email.us-east-1.amazonaws.com') {
77         if (
$accessKey !== null && $secretKey !== null) {
78             
$this->setAuth($accessKey$secretKey);
79         }
80         
$this->__host $host;
81     }
82
83     
/**
84     * Set AWS access key and secret key
85     *
86     * @param string $accessKey Access key
87     * @param string $secretKey Secret key
88     * @return void
89     */
90     
public function setAuth($accessKey$secretKey) {
91         
$this->__accessKey $accessKey;
92         
$this->__secretKey $secretKey;
93     }
94
95     
/**
96     * Lists the email addresses that have been verified and can be used as the 'From' address
97     *
98     * @return An array containing two items: a list of verified email addresses, and the request id.
99     */
100     
public function listVerifiedEmailAddresses() {
101         
$rest = new SimpleEmailServiceRequest($this'GET');
102         
$rest->setParameter('Action''ListVerifiedEmailAddresses');
103
104         
$rest $rest->getResponse();
105         if (
$rest->error === false && $rest->code !== 200) {
106             
$rest->error = array('code' => $rest->code'message' => 'Unexpected HTTP status');
107         }
108         if (
$rest->error !== false) {
109             
$this->__triggerError('listVerifiedEmailAddresses'$rest->error);
110             return 
false;
111         }
112
113         
$response = array();
114         if (!isset(
$rest->body)) {
115             return 
$response;
116         }
117
118         
$addresses = array();
119         foreach(
$rest->body->ListVerifiedEmailAddressesResult->VerifiedEmailAddresses->member as $address) {
120             
$addresses[] = (string)$address;
121         }
122
123         
$response['Addresses'] = $addresses;
124         
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
125
126         return 
$response;
127     }
128
129     
/**
130     * Requests verification of the provided email address, so it can be used
131     * as the 'From' address when sending emails through SimpleEmailService.
132     *
133     * After submitting this request, you should receive a verification email
134     * from Amazon at the specified address containing instructions to follow.
135     *
136     * @param string email The email address to get verified
137     * @return The request id for this request.
138     */
139     
public function verifyEmailAddress($email) {
140         
$rest = new SimpleEmailServiceRequest($this'POST');
141         
$rest->setParameter('Action''VerifyEmailAddress');
142         
$rest->setParameter('EmailAddress'$email);
143
144         
$rest $rest->getResponse();
145         if (
$rest->error === false && $rest->code !== 200) {
146             
$rest->error = array('code' => $rest->code'message' => 'Unexpected HTTP status');
147         }
148         if (
$rest->error !== false) {
149             
$this->__triggerError('verifyEmailAddress'$rest->error);
150             return 
false;
151         }
152
153         
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
154         return 
$response;
155     }
156
157     
/**
158     * Removes the specified email address from the list of verified addresses.
159     *
160     * @param string email The email address to remove
161     * @return The request id for this request.
162     */
163     
public function deleteVerifiedEmailAddress($email) {
164         
$rest = new SimpleEmailServiceRequest($this'DELETE');
165         
$rest->setParameter('Action''DeleteVerifiedEmailAddress');
166         
$rest->setParameter('EmailAddress'$email);
167
168         
$rest $rest->getResponse();
169         if (
$rest->error === false && $rest->code !== 200) {
170             
$rest->error = array('code' => $rest->code'message' => 'Unexpected HTTP status');
171         }
172         if (
$rest->error !== false) {
173             
$this->__triggerError('deleteVerifiedEmailAddress'$rest->error);
174             return 
false;
175         }
176
177         
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
178         return 
$response;
179     }
180
181     
/**
182     * Retrieves information on the current activity limits for this account.
183     * See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendQuota.html
184     *
185     * @return An array containing information on this account's activity limits.
186     */
187     
public function getSendQuota() {
188         
$rest = new SimpleEmailServiceRequest($this'GET');
189         
$rest->setParameter('Action''GetSendQuota');
190
191         
$rest $rest->getResponse();
192         if (
$rest->error === false && $rest->code !== 200) {
193             
$rest->error = array('code' => $rest->code'message' => 'Unexpected HTTP status');
194         }
195         if (
$rest->error !== false) {
196             
$this->__triggerError('getSendQuota'$rest->error);
197             return 
false;
198         }
199
200         
$response = array();
201         if (!isset(
$rest->body)) {
202             return 
$response;
203         }
204
205         
$response['Max24HourSend'] = (string)$rest->body->GetSendQuotaResult->Max24HourSend;
206         
$response['MaxSendRate'] = (string)$rest->body->GetSendQuotaResult->MaxSendRate;
207         
$response['SentLast24Hours'] = (string)$rest->body->GetSendQuotaResult->SentLast24Hours;
208         
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
209
210         return 
$response;
211     }
212
213     
/**
214     * Retrieves statistics for the last two weeks of activity on this account.
215     * See http://docs.amazonwebservices.com/ses/latest/APIReference/API_GetSendStatistics.html
216     *
217     * @return An array of activity statistics.  Each array item covers a 15-minute period.
218     */
219     
public function getSendStatistics() {
220         
$rest = new SimpleEmailServiceRequest($this'GET');
221         
$rest->setParameter('Action''GetSendStatistics');
222
223         
$rest $rest->getResponse();
224         if (
$rest->error === false && $rest->code !== 200) {
225             
$rest->error = array('code' => $rest->code'message' => 'Unexpected HTTP status');
226         }
227         if (
$rest->error !== false) {
228             
$this->__triggerError('getSendStatistics'$rest->error);
229             return 
false;
230         }
231
232         
$response = array();
233         if (!isset(
$rest->body)) {
234             return 
$response;
235         }
236
237         
$datapoints = array();
238         foreach(
$rest->body->GetSendStatisticsResult->SendDataPoints->member as $datapoint) {
239             
$p = array();
240             
$p['Bounces'] = (string)$datapoint->Bounces;
241             
$p['Complaints'] = (string)$datapoint->Complaints;
242             
$p['DeliveryAttempts'] = (string)$datapoint->DeliveryAttempts;
243             
$p['Rejects'] = (string)$datapoint->Rejects;
244             
$p['Timestamp'] = (string)$datapoint->Timestamp;
245
246             
$datapoints[] = $p;
247         }
248
249         
$response['SendDataPoints'] = $datapoints;
250         
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
251
252         return 
$response;
253     }
254
255     
/**
256     * Given a SimpleEmailServiceMessage object, submits the message to the service for sending.
257     *
258     * @return An array containing the unique identifier for this message and a separate request id.
259     *         Returns false if the provided message is missing any required fields.
260     */
261     
public function sendEmail($sesMessage) {
262         if (!
$sesMessage->validate()) {
263             
$this->__triggerError('sendEmail''Message failed validation.');
264             return 
false;
265         }
266
267         
$rest = new SimpleEmailServiceRequest($this'POST');
268         
$rest->setParameter('Action''SendEmail');
269
270         
$i 1;
271         foreach(
$sesMessage->to as $to) {
272             
$rest->setParameter('Destination.ToAddresses.member.'.$i$to);
273             
$i++;
274         }
275
276         if (
is_array($sesMessage->cc)) {
277             
$i 1;
278             foreach(
$sesMessage->cc as $cc) {
279                 
$rest->setParameter('Destination.CcAddresses.member.'.$i$cc);
280                 
$i++;
281             }
282         }
283
284         if (
is_array($sesMessage->bcc)) {
285             
$i 1;
286             foreach(
$sesMessage->bcc as $bcc) {
287                 
$rest->setParameter('Destination.BccAddresses.member.'.$i$bcc);
288                 
$i++;
289             }
290         }
291
292         if (
is_array($sesMessage->replyto)) {
293             
$i 1;
294             foreach(
$sesMessage->replyto as $replyto) {
295                 
$rest->setParameter('ReplyToAddresses.member.'.$i$replyto);
296                 
$i++;
297             }
298         }
299
300         
$rest->setParameter('Source'$sesMessage->from);
301
302         if (
$sesMessage->returnpath != null) {
303             
$rest->setParameter('ReturnPath'$sesMessage->returnpath);
304         }
305
306         if (
$sesMessage->subject != null && strlen($sesMessage->subject) > 0) {
307             
$rest->setParameter('Message.Subject.Data'$sesMessage->subject);
308             if (
$sesMessage->subjectCharset != null && strlen($sesMessage->subjectCharset) > 0) {
309                 
$rest->setParameter('Message.Subject.Charset'$sesMessage->subjectCharset);
310             }
311         }
312
313         if (
$sesMessage->messagetext != null && strlen($sesMessage->messagetext) > 0) {
314             
$rest->setParameter('Message.Body.Text.Data'$sesMessage->messagetext);
315             if (
$sesMessage->messageTextCharset != null && strlen($sesMessage->messageTextCharset) > 0) {
316                 
$rest->setParameter('Message.Body.Text.Charset'$sesMessage->messageTextCharset);
317             }
318         }
319
320         if (
$sesMessage->messagehtml != null && strlen($sesMessage->messagehtml) > 0) {
321             
$rest->setParameter('Message.Body.Html.Data'$sesMessage->messagehtml);
322             if (
$sesMessage->messageHtmlCharset != null && strlen($sesMessage->messageHtmlCharset) > 0) {
323                 
$rest->setParameter('Message.Body.Html.Charset'$sesMessage->messageHtmlCharset);
324             }
325         }
326
327         
$rest $rest->getResponse();
328         if (
$rest->error === false && $rest->code !== 200) {
329             
$rest->error = array('code' => $rest->code'message' => 'Unexpected HTTP status');
330         }
331         if (
$rest->error !== false) {
332             
$this->__triggerError('sendEmail'$rest->error);
333             return 
false;
334         }
335
336         
$response['MessageId'] = (string)$rest->body->SendEmailResult->MessageId;
337         
$response['RequestId'] = (string)$rest->body->ResponseMetadata->RequestId;
338         return 
$response;
339     }
340
341     
/**
342     * Trigger an error message
343     *
344     * @internal Used by member functions to output errors
345     * @param array $error Array containing error information
346     * @return string
347     */
348     
public function __triggerError($functionname$error) {
349         if (
$error == false) {
350             
trigger_error(sprintf("SimpleEmailService::%s(): Encountered an error, but no description given",
 
$functionname), E_USER_WARNING);
351         } else if (isset(
$error['curl']) && $error['curl']) {
352             
trigger_error(sprintf("SimpleEmailService::%s(): %s %s"$functionname$error['code'],
 
$error['message']), E_USER_WARNING);
353         } else if (isset(
$error['Error'])) {
354             
$e $error['Error'];
355             
$message sprintf("SimpleEmailService::%s(): %s - %s: %s\nRequest Id: %s\n"$functionname,
 
$e['Type'], $e['Code'], $e['Message'], $error['RequestId']);
356             
trigger_error($messageE_USER_WARNING);
357         } else {
358             
trigger_error(sprintf("SimpleEmailService::%s(): Encountered an error: %s"$functionname$error),
 
E_USER_WARNING);
359         }
360     }
361 }
362
363 final class 
SimpleEmailServiceRequest {
364     private 
$ses$verb$parameters = array();
365     public 
$response$resource;
366
367     
/**
368     * Constructor
369     *
370     * @param string $ses The SimpleEmailService object making this request
371     * @param string $action action
372     * @param string $verb HTTP verb
373     * @return mixed
374     */
375     
public function __construct($ses$verb) {
376         
$this->ses $ses;
377         
$this->verb $verb;
378         
$this->response = new STDClass;
379         
$this->response->error false;
380     }
381
382     
/**
383     * Set request parameter
384     *
385     * @param string  $key Key
386     * @param string  $value Value
387     * @param boolean $replace Whether to replace the key if it already exists (default true)
388     * @return void
389     */
390     
public function setParameter($key$value$replace true) {
391         if (!
$replace && isset($this->parameters[$key])) {
392             
$temp = (array)($this->parameters[$key]);
393             
$temp[] = $value;
394             
$this->parameters[$key] = $temp;
395         } else {
396             
$this->parameters[$key] = $value;
397         }
398     }
399
400     
/**
401     * Get the response
402     *
403     * @return object | false
404     */
405     
public function getResponse() {
406
407         
$params = array();
408         foreach (
$this->parameters as $var => $value) {
409             if (
is_array($value)) {
410                 foreach(
$value as $v) {
411                     
$params[] = $var.'='.$this->__customUrlEncode($v);
412                 }
413             } else {
414                 
$params[] = $var.'='.$this->__customUrlEncode($value);
415             }
416         }
417
418         
sort($paramsSORT_STRING);
419
420         
// must be in format 'Sun, 06 Nov 1994 08:49:37 GMT'
421         
$date gmdate('D, d M Y H:i:s e');
422
423         
$query implode('&'$params);
424
425         
$headers = array();
426         
$headers[] = 'Date: '.$date;
427         
$headers[] = 'Host: '.$this->ses->getHost();
428
429         
$auth 'AWS3-HTTPS AWSAccessKeyId='.$this->ses->getAccessKey();
430         
$auth .= ',Algorithm=HmacSHA256,Signature='.$this->__getSignature($date);
431         
$headers[] = 'X-Amzn-Authorization: '.$auth;
432
433         
$url 'https://'.$this->ses->getHost().'/';
434
435         
// Basic setup
436         
$curl curl_init();
437         
curl_setopt($curlCURLOPT_USERAGENT'SimpleEmailService/php');
438
439         
curl_setopt($curlCURLOPT_SSL_VERIFYHOST, ($this->ses->verifyHost() ? 0));
440         
curl_setopt($curlCURLOPT_SSL_VERIFYPEER, ($this->ses->verifyPeer() ? 0));
441
442         
// Request types
443         
switch ($this->verb) {
444             case 
'GET':
445                 
$url .= '?'.$query;
446                 break;
447             case 
'POST':
448                 
curl_setopt($curlCURLOPT_CUSTOMREQUEST$this->verb);
449                 
curl_setopt($curlCURLOPT_POSTFIELDS$query);
450                 
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
451             break;
452             case 
'DELETE':
453                 
$url .= '?'.$query;
454                 
curl_setopt($curlCURLOPT_CUSTOMREQUEST'DELETE');
455             break;
456             default: break;
457         }
458         
curl_setopt($curlCURLOPT_HTTPHEADER$headers);
459         
curl_setopt($curlCURLOPT_HEADERfalse);
460
461         
curl_setopt($curlCURLOPT_URL$url);
462         
curl_setopt($curlCURLOPT_RETURNTRANSFERfalse);
463         
curl_setopt($curlCURLOPT_WRITEFUNCTION, array(&$this'__responseWriteCallback'));
464         
curl_setopt($curlCURLOPT_FOLLOWLOCATIONtrue);
465
466         
// Execute, grab errors
467         
if (curl_exec($curl)) {
468             
$this->response->code curl_getinfo($curlCURLINFO_HTTP_CODE);
469         } else {
470             
$this->response->error = array(
471                 
'curl' => true,
472                 
'code' => curl_errno($curl),
473                 
'message' => curl_error($curl),
474                 
'resource' => $this->resource
475             
);
476         }
477
478         @
curl_close($curl);
479
480         
// Parse body into XML
481         
if ($this->response->error === false && isset($this->response->body)) {
482             
$this->response->body simplexml_load_string($this->response->body);
483
484             
// Grab SES errors
485             
if (!in_array($this->response->code, array(200201202204))
486                 && isset(
$this->response->body->Error)) {
487                 
$error $this->response->body->Error;
488                 
$output = array();
489                 
$output['curl'] = false;
490                 
$output['Error'] = array();
491                 
$output['Error']['Type'] = (string)$error->Type;
492                 
$output['Error']['Code'] = (string)$error->Code;
493                 
$output['Error']['Message'] = (string)$error->Message;
494                 
$output['RequestId'] = (string)$this->response->body->RequestId;
495
496                 
$this->response->error $output;
497                 unset(
$this->response->body);
498             }
499         }
500
501         return 
$this->response;
502     }
503
504     
/**
505     * CURL write callback
506     *
507     * @param resource &$curl CURL resource
508     * @param string &$data Data
509     * @return integer
510     */
511     
private function __responseWriteCallback(&$curl, &$data) {
512         
$this->response->body .= $data;
513         return 
strlen($data);
514     }
515
516     
/**
517     * Contributed by afx114
518     * URL encode the parameters as per
 
http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?Query_QueryAuth.html
519     
PHP's rawurlencode() follows RFC 1738, not RFC 3986 as required by Amazon. The only difference is the tilde
 (~), so convert it back after rawurlencode
520     * See: http://www.morganney.com/blog/API/AWS-Product-Advertising-API-Requires-a-Signed-Request.php
521     *
522     * @param string $var String to encode
523     * @return string
524     */
525     private function __customUrlEncode($var) {
526         return str_replace('
%7E', '~', rawurlencode($var));
527     }
528
529     /**
530     * Generate the auth string using Hmac-SHA256
531     *
532     * @internal Used by SimpleDBRequest::getResponse()
533     * @param string $string String to sign
534     * @return string
535     */
536     private function __getSignature($string) {
537         return base64_encode(hash_hmac('
sha256', $string, $this->ses->getSecretKey(), true));
538     }
539 }
540
541 final class SimpleEmailServiceMessage {
542
543     // these are public for convenience only
544     // these are not to be used outside of the SimpleEmailService class!
545     public $to, $cc, $bcc, $replyto;
546     public $from, $returnpath;
547     public $subject, $messagetext, $messagehtml;
548     public $subjectCharset, $messageTextCharset, $messageHtmlCharset;
549
550     public function __construct() {
551         $this->to = array();
552         $this->cc = array();
553         $this->bcc = array();
554         $this->replyto = array();
555
556         $this->from = null;
557         $this->returnpath = null;
558
559         $this->subject = null;
560         $this->messagetext = null;
561         $this->messagehtml = null;
562
563         $this->subjectCharset = null;
564         $this->messageTextCharset = null;
565         $this->messageHtmlCharset = null;
566     }
567
568     /**
569     * addTo, addCC, addBCC, and addReplyTo have the following behavior:
570     * If a single address is passed, it is appended to the current list of addresses.
571     * If an array of addresses is passed, that array is merged into the current list.
572     */
573     public function addTo($to) {
574         if (!is_array($to)) {
575             $this->to[] = $to;
576         } else {
577             $this->to = array_merge($this->to, $to);
578         }
579     }
580
581     public function addCC($cc) {
582         if (!is_array($cc)) {
583             $this->cc[] = $cc;
584         } else {
585             $this->cc = array_merge($this->cc, $cc);
586         }
587     }
588
589     public function addBCC($bcc) {
590         if (!is_array($bcc)) {
591             $this->bcc[] = $bcc;
592         } else {
593             $this->bcc = array_merge($this->bcc, $bcc);
594         }
595     }
596
597     public function addReplyTo($replyto) {
598         if (!is_array($replyto)) {
599             $this->replyto[] = $replyto;
600         } else {
601             $this->replyto = array_merge($this->replyto, $replyto);
602         }
603     }
604
605     public function setFrom($from) {
606         $this->from = $from;
607     }
608
609     public function setReturnPath($returnpath) {
610         $this->returnpath = $returnpath;
611     }
612
613     public function setSubject($subject) {
614         $this->subject = $subject;
615     }
616
617     public function setSubjectCharset($charset) {
618         $this->subjectCharset = $charset;
619     }
620
621     public function setMessageFromString($text, $html = null) {
622         $this->messagetext = $text;
623         $this->messagehtml = $html;
624     }
625
626     public function setMessageFromFile($textfile, $htmlfile = null) {
627         if (file_exists($textfile) && is_file($textfile) && is_readable($textfile)) {
628             $this->messagetext = file_get_contents($textfile);
629         } else {
630             $this->messagetext = null;
631         }
632         if (file_exists($htmlfile) && is_file($htmlfile) && is_readable($htmlfile)) {
633             $this->messagehtml = file_get_contents($htmlfile);
634         } else {
635             $this->messagehtml = null;
636         }
637     }
638
639     public function setMessageFromURL($texturl, $htmlurl = null) {
640         if ($texturl !== null) {
641             $this->messagetext = file_get_contents($texturl);
642         } else {
643             $this->messagetext = null;
644         }
645         if ($htmlurl !== null) {
646             $this->messagehtml = file_get_contents($htmlurl);
647         } else {
648             $this->messagehtml = null;
649         }
650     }
651
652     public function setMessageCharset($textCharset, $htmlCharset = null) {
653         $this->messageTextCharset = $textCharset;
654         $this->messageHtmlCharset = $htmlCharset;
655     }
656
657     /**
658     * Validates whether the message object has sufficient information to submit a request to SES.
659     * This does not guarantee the message will arrive, nor that the request will succeed;
660     * instead, it makes sure that no required fields are missing.
661     *
662     * This is used internally before attempting a SendEmail or SendRawEmail request,
663     * but it can be used outside of this file if verification is desired.
664     * May be useful if e.g. the data is being populated from a form; developers can generally
665     * use this function to verify completeness instead of writing custom logic.
666     *
667     * @return boolean
668     */
669     public function validate() {
670         if (count($this->to) == 0)
671             return false;
672         if ($this->from == null || strlen($this->from) == 0)
673             return false;
674         // messages require at least one of: subject, messagetext, messagehtml.
675         if (($this->subject == null || strlen($this->subject) == 0)
676             && ($this->messagetext == null || strlen($this->messagetext) == 0)
677             && ($this->messagehtml == null || strlen($this->messagehtml) == 0)) {
678             return false;
679         }
680
681         return true;
682     }
683 }