1<?php 2 3/* 4 * This file is part of SwiftMailer. 5 * (c) 2004-2009 Chris Corbyn 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11 12/** 13 * Sends Messages using the mail() function. 14 * 15 * It is advised that users do not use this transport if at all possible 16 * since a number of plugin features cannot be used in conjunction with this 17 * transport due to the internal interface in PHP itself. 18 * 19 * The level of error reporting with this transport is incredibly weak, again 20 * due to limitations of PHP's internal mail() function. You'll get an 21 * all-or-nothing result from sending. 22 * 23 * @package Swift 24 * @subpackage Transport 25 * @author Chris Corbyn 26 */ 27class Swift_Transport_MailTransport implements Swift_Transport 28{ 29 30 /** Addtional parameters to pass to mail() */ 31 private $_extraParams = '-f%s'; 32 33 /** The event dispatcher from the plugin API */ 34 private $_eventDispatcher; 35 36 /** An invoker that calls the mail() function */ 37 private $_invoker; 38 39 /** 40 * Create a new MailTransport with the $log. 41 * @param Swift_Transport_Log $log 42 */ 43 public function __construct(Swift_Transport_MailInvoker $invoker, 44 Swift_Events_EventDispatcher $eventDispatcher) 45 { 46 $this->_invoker = $invoker; 47 $this->_eventDispatcher = $eventDispatcher; 48 } 49 50 /** 51 * Not used. 52 */ 53 public function isStarted() 54 { 55 return false; 56 } 57 58 /** 59 * Not used. 60 */ 61 public function start() 62 { 63 } 64 65 /** 66 * Not used. 67 */ 68 public function stop() 69 { 70 } 71 72 /** 73 * Set the additional parameters used on the mail() function. 74 * 75 * This string is formatted for sprintf() where %s is the sender address. 76 * 77 * @param string $params 78 * @return Swift_Transport_MailTransport 79 */ 80 public function setExtraParams($params) 81 { 82 $this->_extraParams = $params; 83 return $this; 84 } 85 86 /** 87 * Get the additional parameters used on the mail() function. 88 * 89 * This string is formatted for sprintf() where %s is the sender address. 90 * 91 * @return string 92 */ 93 public function getExtraParams() 94 { 95 return $this->_extraParams; 96 } 97 98 /** 99 * Send the given Message. 100 * 101 * Recipient/sender data will be retrieved from the Message API. 102 * The return value is the number of recipients who were accepted for delivery. 103 * 104 * @param Swift_Mime_Message $message 105 * @param string[] &$failedRecipients to collect failures by-reference 106 * @return int 107 */ 108 public function send(Swift_Mime_Message $message, &$failedRecipients = null) 109 { 110 $failedRecipients = (array) $failedRecipients; 111 112 if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) 113 { 114 $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); 115 if ($evt->bubbleCancelled()) 116 { 117 return 0; 118 } 119 } 120 121 $count = ( 122 count((array) $message->getTo()) 123 + count((array) $message->getCc()) 124 + count((array) $message->getBcc()) 125 ); 126 127 $toHeader = $message->getHeaders()->get('To'); 128 $subjectHeader = $message->getHeaders()->get('Subject'); 129 130 if (!$toHeader) 131 { 132 throw new Swift_TransportException( 133 'Cannot send message without a recipient' 134 ); 135 } 136 $to = $toHeader->getFieldBody(); 137 $subject = $subjectHeader ? $subjectHeader->getFieldBody() : ''; 138 139 $reversePath = $this->_getReversePath($message); 140 141 //Remove headers that would otherwise be duplicated 142 $message->getHeaders()->remove('To'); 143 $message->getHeaders()->remove('Subject'); 144 145 $messageStr = $message->toString(); 146 147 $message->getHeaders()->set($toHeader); 148 $message->getHeaders()->set($subjectHeader); 149 150 //Separate headers from body 151 if (false !== $endHeaders = strpos($messageStr, "\r\n\r\n")) 152 { 153 $headers = substr($messageStr, 0, $endHeaders) . "\r\n"; //Keep last EOL 154 $body = substr($messageStr, $endHeaders + 4); 155 } 156 else 157 { 158 $headers = $messageStr . "\r\n"; 159 $body = ''; 160 } 161 162 unset($messageStr); 163 164 if ("\r\n" != PHP_EOL) //Non-windows (not using SMTP) 165 { 166 $headers = str_replace("\r\n", PHP_EOL, $headers); 167 $body = str_replace("\r\n", PHP_EOL, $body); 168 } 169 else //Windows, using SMTP 170 { 171 $headers = str_replace("\r\n.", "\r\n..", $headers); 172 $body = str_replace("\r\n.", "\r\n..", $body); 173 } 174 175 if ($this->_invoker->mail($to, $subject, $body, $headers, 176 sprintf($this->_extraParams, $reversePath))) 177 { 178 if ($evt) 179 { 180 $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); 181 $evt->setFailedRecipients($failedRecipients); 182 $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); 183 } 184 } 185 else 186 { 187 $failedRecipients = array_merge( 188 $failedRecipients, 189 array_keys((array) $message->getTo()), 190 array_keys((array) $message->getCc()), 191 array_keys((array) $message->getBcc()) 192 ); 193 194 if ($evt) 195 { 196 $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); 197 $evt->setFailedRecipients($failedRecipients); 198 $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); 199 } 200 201 $message->generateId(); 202 203 $count = 0; 204 } 205 206 return $count; 207 } 208 209 /** 210 * Register a plugin. 211 * 212 * @param Swift_Events_EventListener $plugin 213 */ 214 public function registerPlugin(Swift_Events_EventListener $plugin) 215 { 216 $this->_eventDispatcher->bindEventListener($plugin); 217 } 218 219 // -- Private methods 220 221 /** Determine the best-use reverse path for this message */ 222 private function _getReversePath(Swift_Mime_Message $message) 223 { 224 $return = $message->getReturnPath(); 225 $sender = $message->getSender(); 226 $from = $message->getFrom(); 227 $path = null; 228 if (!empty($return)) 229 { 230 $path = $return; 231 } 232 elseif (!empty($sender)) 233 { 234 $keys = array_keys($sender); 235 $path = array_shift($keys); 236 } 237 elseif (!empty($from)) 238 { 239 $keys = array_keys($from); 240 $path = array_shift($keys); 241 } 242 return $path; 243 } 244 245} 246