Overview

Packages

  • Mail

Classes

  • Horde_Mail
  • Horde_Mail_Exception
  • Horde_Mail_Rfc822
  • Horde_Mail_Rfc822_Address
  • Horde_Mail_Rfc822_Group
  • Horde_Mail_Rfc822_Object
  • Horde_Mail_Transport
  • Horde_Mail_Transport_Mail
  • Horde_Mail_Transport_Mock
  • Horde_Mail_Transport_Null
  • Horde_Mail_Transport_Sendmail
  • Horde_Mail_Transport_Smtp
  • Horde_Mail_Transport_Smtpmx
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Sendmail interface.
  4:  *
  5:  * LICENSE:
  6:  *
  7:  * Copyright (c) 2010 Chuck Hagenbuch
  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
 12:  * are met:
 13:  *
 14:  * o Redistributions of source code must retain the above copyright
 15:  *   notice, this list of conditions and the following disclaimer.
 16:  * o Redistributions in binary form must reproduce the above copyright
 17:  *   notice, this list of conditions and the following disclaimer in the
 18:  *   documentation and/or other materials provided with the distribution.
 19:  * o The names of the authors may not be used to endorse or promote
 20:  *   products derived from this software without specific prior written
 21:  *   permission.
 22:  *
 23:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 24:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 25:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 26:  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 27:  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 28:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 29:  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 30:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 31:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 32:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 33:  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 34:  *
 35:  * @category  Horde
 36:  * @package   Mail
 37:  * @author    Chuck Hagenbuch <chuck@horde.org>
 38:  * @author    Michael Slusarz <slusarz@horde.org>
 39:  * @copyright 2010 Chuck Hagenbuch
 40:  * @copyright 2010 Michael Slusarz
 41:  * @license   http://www.horde.org/licenses/bsd New BSD License
 42:  */
 43: 
 44: /**
 45:  * Sendmail interface.
 46:  *
 47:  * @category Horde
 48:  * @package  Mail
 49:  */
 50: class Horde_Mail_Transport_Sendmail extends Horde_Mail_Transport
 51: {
 52:     /**
 53:      * Any extra command-line parameters to pass to the sendmail or
 54:      * sendmail wrapper binary.
 55:      *
 56:      * @var string
 57:      */
 58:     protected $_sendmailArgs = '-i';
 59: 
 60:     /**
 61:      * The location of the sendmail or sendmail wrapper binary on the
 62:      * filesystem.
 63:      *
 64:      * @var string
 65:      */
 66:     protected $_sendmailPath = '/usr/sbin/sendmail';
 67: 
 68:     /**
 69:      * Constructor.
 70:      *
 71:      * @param array $params  Additional parameters:
 72:      *   - sendmail_args: (string) Any extra parameters to pass to the sendmail
 73:      *                    or sendmail wrapper binary.
 74:      *                    DEFAULT: -i
 75:      *   - sendmail_path: (string) The location of the sendmail binary on the
 76:      *                    filesystem.
 77:      *                    DEFAULT: /usr/sbin/sendmail
 78:      */
 79:     public function __construct(array $params = array())
 80:     {
 81:         if (isset($params['sendmail_args'])) {
 82:             $this->_sendmailArgs = $params['sendmail_args'];
 83:         }
 84: 
 85:         if (isset($params['sendmail_path'])) {
 86:             $this->_sendmailPath = $params['sendmail_path'];
 87:         }
 88:     }
 89: 
 90:     /**
 91:      * Send a message.
 92:      *
 93:      * @param mixed $recipients  Either a comma-seperated list of recipients
 94:      *                           (RFC822 compliant), or an array of
 95:      *                           recipients, each RFC822 valid. This may
 96:      *                           contain recipients not specified in the
 97:      *                           headers, for Bcc:, resending messages, etc.
 98:      * @param array $headers     The headers to send with the mail, in an
 99:      *                           associative array, where the array key is the
100:      *                           header name (ie, 'Subject'), and the array
101:      *                           value is the header value (ie, 'test'). The
102:      *                           header produced from those values would be
103:      *                           'Subject: test'.
104:      *                           If the '_raw' key exists, the value of this
105:      *                           key will be used as the exact text for
106:      *                           sending the message.
107:      * @param mixed $body        The full text of the message body, including
108:      *                           any Mime parts, etc. Either a string or a
109:      *                           stream resource.
110:      *
111:      * @throws Horde_Mail_Exception
112:      */
113:     public function send($recipients, array $headers, $body)
114:     {
115:         $recipients = implode(' ', array_map('escapeshellarg', $this->parseRecipients($recipients)));
116: 
117:         $headers = $this->_sanitizeHeaders($headers);
118:         list($from, $text_headers) = $this->prepareHeaders($headers);
119: 
120:         /* Since few MTAs are going to allow this header to be forged
121:          * unless it's in the MAIL FROM: exchange, we'll use Return-Path
122:          * instead of From: if it's set. */
123:         foreach (array_keys($headers) as $hdr) {
124:             if (strcasecmp($hdr, 'Return-Path') === 0) {
125:                 $from = $headers[$hdr];
126:                 break;
127:             }
128:         }
129: 
130:         if (!strlen($from)) {
131:             throw new Horde_Mail_Exception('No From address given.');
132:         } elseif ((strpos($from, ' ') !== false) ||
133:                   (strpos($from, ';') !== false) ||
134:                   (strpos($from, '&') !== false) ||
135:                   (strpos($from, '`') !== false)) {
136:             throw new Horde_Mail_Exception('From address specified with dangerous characters.');
137:         }
138: 
139:         $mail = @popen($this->_sendmailPath . (empty($this->_sendmailArgs) ? '' : ' ' . $this->_sendmailArgs) . ' -f ' . escapeshellarg($from) . ' -- ' . $recipients, 'w');
140:         if (!$mail) {
141:             throw new Horde_Mail_Exception('Failed to open sendmail [' . $this->_sendmailPath . '] for execution.');
142:         }
143: 
144:         // Write the headers following by two newlines: one to end the headers
145:         // section and a second to separate the headers block from the body.
146:         fputs($mail, $text_headers . $this->sep . $this->sep);
147: 
148:         if (is_resource($body)) {
149:             stream_filter_register('horde_eol', 'Horde_Stream_Filter_Eol');
150:             stream_filter_append($body, 'horde_eol', STREAM_FILTER_READ, array('eol' => $this->sep));
151: 
152:             rewind($body);
153:             while (!feof($body)) {
154:                 fputs($mail, fread($body, 8192));
155:             }
156:         } else {
157:             fputs($mail, $this->_normalizeEOL($body));
158:         }
159:         $result = pclose($mail);
160: 
161:         if (!$result) {
162:             return;
163:         }
164: 
165:         switch ($result) {
166:         case 64: // EX_USAGE
167:             $msg = 'command line usage error';
168:             break;
169: 
170:         case 65: // EX_DATAERR
171:             $msg =  'data format error';
172:             break;
173: 
174:         case 66: // EX_NOINPUT
175:             $msg = 'cannot open input';
176:             break;
177: 
178:         case 67: // EX_NOUSER
179:             $msg = 'addressee unknown';
180:             break;
181: 
182:         case 68: // EX_NOHOST
183:             $msg = 'host name unknown';
184:             break;
185: 
186:         case 69: // EX_UNAVAILABLE
187:             $msg = 'service unavailable';
188:             break;
189: 
190:         case 70: // EX_SOFTWARE
191:             $msg = 'internal software error';
192:             break;
193: 
194:         case 71: // EX_OSERR
195:             $msg = 'system error';
196:             break;
197: 
198:         case 72: // EX_OSFILE
199:             $msg = 'critical system file missing';
200:             break;
201: 
202:         case 73: // EX_CANTCREAT
203:             $msg = 'cannot create output file';
204:             break;
205: 
206:         case 74: // EX_IOERR
207:             $msg = 'input/output error';
208: 
209:         case 75: // EX_TEMPFAIL
210:             $msg = 'temporary failure';
211:             break;
212: 
213:         case 76: // EX_PROTOCOL
214:             $msg = 'remote error in protocol';
215:             break;
216: 
217:         case 77: // EX_NOPERM
218:             $msg = 'permission denied';
219:             break;
220: 
221:         case 77: // EX_NOPERM
222:             $msg = 'permission denied';
223:             break;
224: 
225:         case 78: // EX_CONFIG
226:             $msg = 'configuration error';
227:             break;
228: 
229:         case 79: // EX_NOTFOUND
230:             $msg = 'entry not found';
231:             break;
232: 
233:         default:
234:             $msg = 'unknown error';
235:             break;
236:         }
237: 
238:         throw new Horde_Mail_Exception('sendmail: ' . $msg . ' (' . $result . ')', $result);
239:     }
240: }
241: 
API documentation generated by ApiGen