Packages

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • none

Classes

Interfaces

Exceptions

  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  * @package Nette\Mail
  7:  */
  8: 
  9: 
 10: 
 11: /**
 12:  * Mail provides functionality to compose and send both text and MIME-compliant multipart email messages.
 13:  *
 14:  * @author     David Grudl
 15:  *
 16:  * @property   array $from
 17:  * @property   string $subject
 18:  * @property   string $returnPath
 19:  * @property   int $priority
 20:  * @property   mixed $htmlBody
 21:  * @property   IMailer $mailer
 22:  * @package Nette\Mail
 23:  */
 24: class NMail extends NMailMimePart
 25: {
 26:     /** Priority */
 27:     const HIGH = 1,
 28:         NORMAL = 3,
 29:         LOW = 5;
 30: 
 31:     /** @var IMailer */
 32:     public static $defaultMailer = 'NSendmailMailer';
 33: 
 34:     /** @var array */
 35:     public static $defaultHeaders = array(
 36:         'MIME-Version' => '1.0',
 37:         'X-Mailer' => 'Nette Framework',
 38:     );
 39: 
 40:     /** @var IMailer */
 41:     private $mailer;
 42: 
 43:     /** @var array */
 44:     private $attachments = array();
 45: 
 46:     /** @var array */
 47:     private $inlines = array();
 48: 
 49:     /** @var mixed */
 50:     private $html;
 51: 
 52:     /** @var string */
 53:     private $basePath;
 54: 
 55: 
 56:     public function __construct()
 57:     {
 58:         foreach (self::$defaultHeaders as $name => $value) {
 59:             $this->setHeader($name, $value);
 60:         }
 61:         $this->setHeader('Date', date('r'));
 62:     }
 63: 
 64: 
 65:     /**
 66:      * Sets the sender of the message.
 67:      * @param  string  email or format "John Doe" <doe@example.com>
 68:      * @param  string
 69:      * @return self
 70:      */
 71:     public function setFrom($email, $name = NULL)
 72:     {
 73:         $this->setHeader('From', $this->formatEmail($email, $name));
 74:         return $this;
 75:     }
 76: 
 77: 
 78:     /**
 79:      * Returns the sender of the message.
 80:      * @return array
 81:      */
 82:     public function getFrom()
 83:     {
 84:         return $this->getHeader('From');
 85:     }
 86: 
 87: 
 88:     /**
 89:      * Adds the reply-to address.
 90:      * @param  string  email or format "John Doe" <doe@example.com>
 91:      * @param  string
 92:      * @return self
 93:      */
 94:     public function addReplyTo($email, $name = NULL)
 95:     {
 96:         $this->setHeader('Reply-To', $this->formatEmail($email, $name), TRUE);
 97:         return $this;
 98:     }
 99: 
100: 
101:     /**
102:      * Sets the subject of the message.
103:      * @param  string
104:      * @return self
105:      */
106:     public function setSubject($subject)
107:     {
108:         $this->setHeader('Subject', $subject);
109:         return $this;
110:     }
111: 
112: 
113:     /**
114:      * Returns the subject of the message.
115:      * @return string
116:      */
117:     public function getSubject()
118:     {
119:         return $this->getHeader('Subject');
120:     }
121: 
122: 
123:     /**
124:      * Adds email recipient.
125:      * @param  string  email or format "John Doe" <doe@example.com>
126:      * @param  string
127:      * @return self
128:      */
129:     public function addTo($email, $name = NULL) // addRecipient()
130:     {
131:         $this->setHeader('To', $this->formatEmail($email, $name), TRUE);
132:         return $this;
133:     }
134: 
135: 
136:     /**
137:      * Adds carbon copy email recipient.
138:      * @param  string  email or format "John Doe" <doe@example.com>
139:      * @param  string
140:      * @return self
141:      */
142:     public function addCc($email, $name = NULL)
143:     {
144:         $this->setHeader('Cc', $this->formatEmail($email, $name), TRUE);
145:         return $this;
146:     }
147: 
148: 
149:     /**
150:      * Adds blind carbon copy email recipient.
151:      * @param  string  email or format "John Doe" <doe@example.com>
152:      * @param  string
153:      * @return self
154:      */
155:     public function addBcc($email, $name = NULL)
156:     {
157:         $this->setHeader('Bcc', $this->formatEmail($email, $name), TRUE);
158:         return $this;
159:     }
160: 
161: 
162:     /**
163:      * Formats recipient email.
164:      * @param  string
165:      * @param  string
166:      * @return array
167:      */
168:     private function formatEmail($email, $name)
169:     {
170:         if (!$name && preg_match('#^(.+) +<(.*)>\z#', $email, $matches)) {
171:             return array($matches[2] => $matches[1]);
172:         } else {
173:             return array($email => $name);
174:         }
175:     }
176: 
177: 
178:     /**
179:      * Sets the Return-Path header of the message.
180:      * @param  string  email
181:      * @return self
182:      */
183:     public function setReturnPath($email)
184:     {
185:         $this->setHeader('Return-Path', $email);
186:         return $this;
187:     }
188: 
189: 
190:     /**
191:      * Returns the Return-Path header.
192:      * @return string
193:      */
194:     public function getReturnPath()
195:     {
196:         return $this->getHeader('Return-Path');
197:     }
198: 
199: 
200:     /**
201:      * Sets email priority.
202:      * @param  int
203:      * @return self
204:      */
205:     public function setPriority($priority)
206:     {
207:         $this->setHeader('X-Priority', (int) $priority);
208:         return $this;
209:     }
210: 
211: 
212:     /**
213:      * Returns email priority.
214:      * @return int
215:      */
216:     public function getPriority()
217:     {
218:         return $this->getHeader('X-Priority');
219:     }
220: 
221: 
222:     /**
223:      * Sets HTML body.
224:      * @param  string|ITemplate
225:      * @param  mixed base-path or FALSE to disable parsing
226:      * @return self
227:      */
228:     public function setHtmlBody($html, $basePath = NULL)
229:     {
230:         $this->html = $html;
231:         $this->basePath = $basePath;
232:         return $this;
233:     }
234: 
235: 
236:     /**
237:      * Gets HTML body.
238:      * @return mixed
239:      */
240:     public function getHtmlBody()
241:     {
242:         return $this->html;
243:     }
244: 
245: 
246:     /**
247:      * Adds embedded file.
248:      * @param  string
249:      * @param  string
250:      * @param  string
251:      * @return NMailMimePart
252:      */
253:     public function addEmbeddedFile($file, $content = NULL, $contentType = NULL)
254:     {
255:         return $this->inlines[$file] = $this->createAttachment($file, $content, $contentType, 'inline')
256:             ->setHeader('Content-ID', $this->getRandomId());
257:     }
258: 
259: 
260:     /**
261:      * Adds attachment.
262:      * @param  string
263:      * @param  string
264:      * @param  string
265:      * @return NMailMimePart
266:      */
267:     public function addAttachment($file, $content = NULL, $contentType = NULL)
268:     {
269:         return $this->attachments[] = $this->createAttachment($file, $content, $contentType, 'attachment');
270:     }
271: 
272: 
273:     /**
274:      * Creates file MIME part.
275:      * @return NMailMimePart
276:      */
277:     private function createAttachment($file, $content, $contentType, $disposition)
278:     {
279:         $part = new NMailMimePart;
280:         if ($content === NULL) {
281:             $content = @file_get_contents($file); // intentionally @
282:             if ($content === FALSE) {
283:                 throw new FileNotFoundException("Unable to read file '$file'.");
284:             }
285:         } else {
286:             $content = (string) $content;
287:         }
288:         $part->setBody($content);
289:         $part->setContentType($contentType ? $contentType : NMimeTypeDetector::fromString($content));
290:         $part->setEncoding(preg_match('#(multipart|message)/#A', $contentType) ? self::ENCODING_8BIT : self::ENCODING_BASE64);
291:         $part->setHeader('Content-Disposition', $disposition . '; filename="' . NStrings::fixEncoding(basename($file)) . '"');
292:         return $part;
293:     }
294: 
295: 
296:     /********************* building and sending ****************d*g**/
297: 
298: 
299:     /**
300:      * Sends email.
301:      * @return void
302:      */
303:     public function send()
304:     {
305:         $this->getMailer()->send($this->build());
306:     }
307: 
308: 
309:     /**
310:      * Sets the mailer.
311:      * @return self
312:      */
313:     public function setMailer(IMailer $mailer)
314:     {
315:         $this->mailer = $mailer;
316:         return $this;
317:     }
318: 
319: 
320:     /**
321:      * Returns mailer.
322:      * @return IMailer
323:      */
324:     public function getMailer()
325:     {
326:         if ($this->mailer === NULL) {
327:             $this->mailer = is_object(self::$defaultMailer) ? self::$defaultMailer : new self::$defaultMailer;
328:         }
329:         return $this->mailer;
330:     }
331: 
332: 
333:     /**
334:      * Returns encoded message.
335:      * @return string
336:      */
337:     public function generateMessage()
338:     {
339:         if ($this->getHeader('Message-ID')) {
340:             return parent::generateMessage();
341:         } else {
342:             return $this->build()->generateMessage();
343:         }
344:     }
345: 
346: 
347:     /**
348:      * Builds email. Does not modify itself, but returns a new object.
349:      * @return NMail
350:      */
351:     protected function build()
352:     {
353:         $mail = clone $this;
354:         $mail->setHeader('Message-ID', $this->getRandomId());
355: 
356:         $mail->buildHtml();
357:         $mail->buildText();
358: 
359:         $cursor = $mail;
360:         if ($mail->attachments) {
361:             $tmp = $cursor->setContentType('multipart/mixed');
362:             $cursor = $cursor->addPart();
363:             foreach ($mail->attachments as $value) {
364:                 $tmp->addPart($value);
365:             }
366:         }
367: 
368:         if ($mail->html != NULL) { // intentionally ==
369:             $tmp = $cursor->setContentType('multipart/alternative');
370:             $cursor = $cursor->addPart();
371:             $alt = $tmp->addPart();
372:             if ($mail->inlines) {
373:                 $tmp = $alt->setContentType('multipart/related');
374:                 $alt = $alt->addPart();
375:                 foreach ($mail->inlines as $value) {
376:                     $tmp->addPart($value);
377:                 }
378:             }
379:             $alt->setContentType('text/html', 'UTF-8')
380:                 ->setEncoding(preg_match('#[^\n]{990}#', $mail->html)
381:                     ? self::ENCODING_QUOTED_PRINTABLE
382:                     : (preg_match('#[\x80-\xFF]#', $mail->html) ? self::ENCODING_8BIT : self::ENCODING_7BIT))
383:                 ->setBody($mail->html);
384:         }
385: 
386:         $text = $mail->getBody();
387:         $mail->setBody(NULL);
388:         $cursor->setContentType('text/plain', 'UTF-8')
389:             ->setEncoding(preg_match('#[^\n]{990}#', $text)
390:                 ? self::ENCODING_QUOTED_PRINTABLE
391:                 : (preg_match('#[\x80-\xFF]#', $text) ? self::ENCODING_8BIT : self::ENCODING_7BIT))
392:             ->setBody($text);
393: 
394:         return $mail;
395:     }
396: 
397: 
398:     /**
399:      * Builds HTML content.
400:      * @return void
401:      */
402:     protected function buildHtml()
403:     {
404:         if ($this->html instanceof ITemplate) {
405:             $this->html->mail = $this;
406:             if ($this->basePath === NULL && $this->html instanceof IFileTemplate) {
407:                 $this->basePath = dirname($this->html->getFile());
408:             }
409:             $this->html = $this->html->__toString(TRUE);
410:         }
411: 
412:         if ($this->basePath !== FALSE) {
413:             $cids = array();
414:             $matches = NStrings::matchAll(
415:                 $this->html,
416:                 '#(src\s*=\s*|background\s*=\s*|url\()(["\'])(?![a-z]+:|[/\\#])(.+?)\\2#i',
417:                 PREG_OFFSET_CAPTURE
418:             );
419:             foreach (array_reverse($matches) as $m) {
420:                 $file = rtrim($this->basePath, '/\\') . '/' . urldecode($m[3][0]);
421:                 if (!isset($cids[$file])) {
422:                     $cids[$file] = substr($this->addEmbeddedFile($file)->getHeader("Content-ID"), 1, -1);
423:                 }
424:                 $this->html = substr_replace($this->html,
425:                     "{$m[1][0]}{$m[2][0]}cid:{$cids[$file]}{$m[2][0]}",
426:                     $m[0][1], strlen($m[0][0])
427:                 );
428:             }
429:         }
430: 
431:         if (!$this->getSubject() && $matches = NStrings::match($this->html, '#<title>(.+?)</title>#is')) {
432:             $this->setSubject(html_entity_decode($matches[1], ENT_QUOTES, 'UTF-8'));
433:         }
434:     }
435: 
436: 
437:     /**
438:      * Builds text content.
439:      * @return void
440:      */
441:     protected function buildText()
442:     {
443:         $text = $this->getBody();
444:         if ($text instanceof ITemplate) {
445:             $text->mail = $this;
446:             $this->setBody($text->__toString(TRUE));
447: 
448:         } elseif ($text == NULL && $this->html != NULL) { // intentionally ==
449:             $text = NStrings::replace($this->html, array(
450:                 '#<(style|script|head).*</\\1>#Uis' => '',
451:                 '#<t[dh][ >]#i' => " $0",
452:                 '#[\r\n]+#' => ' ',
453:                 '#<(/?p|/?h\d|li|br|/tr)[ >/]#i' => "\n$0",
454:             ));
455:             $text = html_entity_decode(strip_tags($text), ENT_QUOTES, 'UTF-8');
456:             $text = NStrings::replace($text, '#[ \t]+#', ' ');
457:             $this->setBody(trim($text));
458:         }
459:     }
460: 
461: 
462:     /** @return string */
463:     private function getRandomId()
464:     {
465:         return '<' . NStrings::random() . '@'
466:             . preg_replace('#[^\w.-]+#', '', isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : php_uname('n'))
467:             . '>';
468:     }
469: 
470: }
471: 
Nette Framework 2.0.18 (for PHP 5.2, prefixed) API documentation generated by ApiGen 2.8.0