Skip to content

Commit

Permalink
Remove PHP mail() support, smtp_server is required now (#5340)
Browse files Browse the repository at this point in the history
  • Loading branch information
alecpl committed Jul 15, 2016
1 parent 8e65f61 commit ee895a2
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 152 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail
===========================

- Remove PHP mail() support, smtp_server is required now (#5340)
- Display full message subject in onmouseover on truncated subject in mail view (#5346)
- Searching in both contacts and groups when LDAP addressbook with group_filters option is used
- Update TinyMCE to version 4.3.13 (#5309)
Expand Down
2 changes: 1 addition & 1 deletion INSTALL
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ REQUIREMENTS
* A MySQL (4.0.8 or newer), PostgreSQL, MS SQL Server (2005 or newer), Oracle
database or SQLite support in PHP
* One of the above databases with permission to create tables
* An SMTP server (recommended) or PHP configured for mail delivery
* An SMTP server
* Composer installed either locally or globally (https://getcomposer.org)


Expand Down
3 changes: 1 addition & 2 deletions config/defaults.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,14 @@

// SMTP server host (for sending mails).
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// If left blank, the PHP mail() function is used
// Supported replacement variables:
// %h - user's IMAP hostname
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %z - IMAP domain (IMAP hostname without the first part)
// For example %n = mail.domain.tld, %t = domain.tld
$config['smtp_server'] = '';
$config['smtp_server'] = 'localhost';

// SMTP port (default is 25; use 587 for STARTTLS or 465 for the
// deprecated SSL over SMTP (aka SMTPS))
Expand Down
4 changes: 2 additions & 2 deletions installer/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -461,12 +461,12 @@
<?php

$text_smtphost = new html_inputfield(array('name' => '_smtp_server', 'size' => 30, 'id' => "cfgsmtphost"));
echo $text_smtphost->show($RCI->getprop('smtp_server'));
echo $text_smtphost->show($RCI->getprop('smtp_server', 'localhost'));

?>
<div>Use this host for sending mails</div>

<p class="hint">To use SSL connection, set ssl://smtp.host.com. If left blank, the PHP mail() function is used</p>
<p class="hint">To use SSL connection, set ssl://smtp.host.com.</p>
</dd>

<dt class="propname">smtp_port</dt>
Expand Down
51 changes: 18 additions & 33 deletions installer/test.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,15 +246,15 @@
<h3>Test SMTP config</h3>

<p>
Server: <?php echo rcube_utils::parse_host($RCI->getprop('smtp_server', 'PHP mail()')); ?><br />
Server: <?php echo rcube_utils::parse_host($RCI->getprop('smtp_server', 'localhost')); ?><br />
Port: <?php echo $RCI->getprop('smtp_port'); ?><br />

<?php

if ($RCI->getprop('smtp_server')) {
$user = $RCI->getprop('smtp_user', '(none)');
$pass = $RCI->getprop('smtp_pass', '(none)');

if ($user == '%u') {
$user_field = new html_inputfield(array('name' => '_smtp_user'));
$user = $user_field->show($_POST['_smtp_user']);
Expand All @@ -263,7 +263,7 @@
$pass_field = new html_passwordfield(array('name' => '_smtp_pass'));
$pass = $pass_field->show();
}

echo "User: $user<br />";
echo "Password: $pass<br />";
}
Expand Down Expand Up @@ -293,42 +293,27 @@
);

$body = 'This is a test to confirm that Roundcube can send email.';
$smtp_response = array();

// send mail using configured SMTP server
if ($RCI->getprop('smtp_server')) {
$CONFIG = $RCI->config;
$CONFIG = $RCI->config;

if (!empty($_POST['_smtp_user'])) {
$CONFIG['smtp_user'] = $_POST['_smtp_user'];
}
if (!empty($_POST['_smtp_pass'])) {
$CONFIG['smtp_pass'] = $_POST['_smtp_pass'];
}

$mail_object = new Mail_mime();
$send_headers = $mail_object->headers($headers);
if (!empty($_POST['_smtp_user'])) {
$CONFIG['smtp_user'] = $_POST['_smtp_user'];
}
if (!empty($_POST['_smtp_pass'])) {
$CONFIG['smtp_pass'] = $_POST['_smtp_pass'];
}

$SMTP = new rcube_smtp();
$SMTP->connect(rcube_utils::parse_host($RCI->getprop('smtp_server')),
$RCI->getprop('smtp_port'), $CONFIG['smtp_user'], $CONFIG['smtp_pass']);
$mail_object = new Mail_mime();
$send_headers = $mail_object->headers($headers);
$head = $mail_object->txtHeaders($send_headers);

$status = $SMTP->send_mail($headers['From'], $headers['To'],
($foo = $mail_object->txtHeaders($send_headers)), $body);
$SMTP = new rcube_smtp();
$SMTP->connect(rcube_utils::parse_host($RCI->getprop('smtp_server')),
$RCI->getprop('smtp_port'), $CONFIG['smtp_user'], $CONFIG['smtp_pass']);

$smtp_response = $SMTP->get_response();
}
else { // use mail()
$header_str = 'From: ' . $headers['From'];

if (ini_get('safe_mode'))
$status = mail($headers['To'], $headers['Subject'], $body, $header_str);
else
$status = mail($headers['To'], $headers['Subject'], $body, $header_str, '-f'.$headers['From']);

if (!$status)
$smtp_response[] = 'Mail delivery with mail() failed. Check your error logs for details';
}
$status = $SMTP->send_mail($headers['From'], $headers['To'], $head, $body);
$smtp_response = $SMTP->get_response();

if ($status) {
$RCI->pass('SMTP send');
Expand Down
149 changes: 41 additions & 108 deletions program/lib/Roundcube/rcube.php
Original file line number Diff line number Diff line change
Expand Up @@ -1548,115 +1548,66 @@ public function deliver_message(&$message, $from, $mailto, &$error, &$body_file
$message = $plugin['message'];
$headers = $message->headers();

// send thru SMTP server using custom SMTP library
if ($this->config->get('smtp_server')) {
// generate list of recipients
$a_recipients = (array) $mailto;

if (strlen($headers['Cc']))
$a_recipients[] = $headers['Cc'];
if (strlen($headers['Bcc']))
$a_recipients[] = $headers['Bcc'];

// remove Bcc header and get the whole head of the message as string
$smtp_headers = $this->message_head($message, array('Bcc'));

if ($message->getParam('delay_file_io')) {
// use common temp dir
$temp_dir = $this->config->get('temp_dir');
$body_file = tempnam($temp_dir, 'rcmMsg');
$mime_result = $message->saveMessageBody($body_file);

if (is_a($mime_result, 'PEAR_Error')) {
self::raise_error(array('code' => 650, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Could not create message: ".$mime_result->getMessage()),
true, false);
return false;
}

$msg_body = fopen($body_file, 'r');
}
else {
$msg_body = $message->get();
}

// send message
if (!is_object($this->smtp)) {
$this->smtp_init(true);
}

$sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $options);
$response = $this->smtp->get_response();
$error = $this->smtp->get_error();
// generate list of recipients
$a_recipients = (array) $mailto;

// log error
if (!$sent) {
self::raise_error(array('code' => 800, 'type' => 'smtp',
'line' => __LINE__, 'file' => __FILE__,
'message' => join("\n", $response)), true, false);
}
if (strlen($headers['Cc'])) {
$a_recipients[] = $headers['Cc'];
}
if (strlen($headers['Bcc'])) {
$a_recipients[] = $headers['Bcc'];
}
// send mail using PHP's mail() function
else {
// unset To,Subject headers because they will be added by the mail() function
$header_str = $this->message_head($message, array('To', 'Subject'));

if (is_array($mailto)) {
$mailto = implode(', ', $mailto);
}

// #1485779
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m)) {
$mailto = implode(', ', $m[1]);
}
}
// remove Bcc header and get the whole head of the message as string
$smtp_headers = $message->txtHeaders(array('Bcc' => null), true);

$msg_body = $message->get();
if ($message->getParam('delay_file_io')) {
// use common temp dir
$temp_dir = $this->config->get('temp_dir');
$body_file = tempnam($temp_dir, 'rcmMsg');
$mime_result = $message->saveMessageBody($body_file);

if (is_a($msg_body, 'PEAR_Error')) {
if (is_a($mime_result, 'PEAR_Error')) {
self::raise_error(array('code' => 650, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Could not create message: ".$msg_body->getMessage()),
'message' => "Could not create message: ".$mime_result->getMessage()),
true, false);
return false;
}
else {
$delim = $this->config->header_delimiter();
$to = $mailto;
$subject = $headers['Subject'];
$header_str = rtrim($header_str);

if ($delim != "\r\n") {
$header_str = str_replace("\r\n", $delim, $header_str);
$msg_body = str_replace("\r\n", $delim, $msg_body);
$to = str_replace("\r\n", $delim, $to);
$subject = str_replace("\r\n", $delim, $subject);
}

$opts = filter_var(ini_get('safe_mode'), FILTER_VALIDATE_BOOLEAN) ? null : "-f$from";
$sent = mail($to, $subject, $msg_body, $header_str, $opts);
}
$msg_body = fopen($body_file, 'r');
}
else {
$msg_body = $message->get();
}

if ($sent) {
// initialize SMTP connection
if (!is_object($this->smtp)) {
$this->smtp_init(true);
}

// send message
$sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $options);
$response = $this->smtp->get_response();
$error = $this->smtp->get_error();

if (!$sent) {
self::raise_error(array('code' => 800, 'type' => 'smtp',
'line' => __LINE__, 'file' => __FILE__,
'message' => join("\n", $response)), true, false);

// allow plugins to catch sending errors with the same parameters as in 'message_before_send'
$this->plugins->exec_hook('message_send_error', $plugin + array('error' => $error));
}
else {
$this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body));

// remove MDN headers after sending
unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']);

if ($this->config->get('smtp_log')) {
// get all recipient addresses
if (is_array($mailto)) {
$mailto = implode(',', $mailto);
}
if ($headers['Cc']) {
$mailto .= ',' . $headers['Cc'];
}
if ($headers['Bcc']) {
$mailto .= ',' . $headers['Bcc'];
}

$mailto = implode(',', $a_recipients);
$mailto = rcube_mime::decode_address_list($mailto, null, false, null, true);

self::write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s",
Expand All @@ -1666,10 +1617,6 @@ public function deliver_message(&$message, $from, $mailto, &$error, &$body_file
!empty($response) ? join('; ', $response) : ''));
}
}
else {
// allow plugins to catch sending errors with the same parameters as in 'message_before_send'
$this->plugins->exec_hook('message_send_error', $plugin + array('error' => $error));
}

if (is_resource($msg_body)) {
fclose($msg_body);
Expand All @@ -1679,20 +1626,6 @@ public function deliver_message(&$message, $from, $mailto, &$error, &$body_file

return $sent;
}

/**
* Return message headers as a string
*/
protected function message_head($message, $unset = array())
{
// requires Mail_mime >= 1.9.0
$headers = array();
foreach ((array) $unset as $header) {
$headers[$header] = null;
}

return $message->txtHeaders($headers, true);
}
}


Expand Down
4 changes: 1 addition & 3 deletions program/steps/mail/sendmail.inc
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,7 @@ $MAIL_MIME = new Mail_mime("\r\n");

// Check if we have enough memory to handle the message in it
// It's faster than using files, so we'll do this if we only can
if (is_array($COMPOSE['attachments']) && $RCMAIL->config->get('smtp_server')
&& ($mem_limit = parse_bytes(ini_get('memory_limit')))
) {
if (is_array($COMPOSE['attachments']) && ($mem_limit = parse_bytes(ini_get('memory_limit')))) {
$memory = 0;
foreach ($COMPOSE['attachments'] as $id => $attachment) {
$memory += $attachment['size'];
Expand Down
2 changes: 1 addition & 1 deletion program/steps/settings/func.inc
Original file line number Diff line number Diff line change
Expand Up @@ -749,7 +749,7 @@ function rcmail_user_prefs($current = null)
);
}

if (!isset($no_override['dsn_default']) && $RCMAIL->config->get('smtp_server')) {
if (!isset($no_override['dsn_default'])) {
if (!$current) {
continue 2;
}
Expand Down
2 changes: 1 addition & 1 deletion skins/classic/templates/compose.html
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@
<td><roundcube:object name="mdnCheckBox" form="form" id="rcmcomposereceipt" /></td>
</tr>
<roundcube:endif />
<roundcube:if condition="config:smtp_server != '' and !in_array('dsn_default', (array)config:dont_override)" />
<roundcube:if condition="!in_array('dsn_default', (array)config:dont_override)" />
<tr>
<td><label for="rcmcomposedsn"><roundcube:label name="dsn" />:</label></td>
<td><roundcube:object name="dsnCheckBox" form="form" id="rcmcomposedsn" /></td>
Expand Down
2 changes: 1 addition & 1 deletion skins/larry/templates/compose.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ <h2 id="aria-label-composeoptions" class="voice"><roundcube:label name="arialabe
<label><roundcube:object name="mdnCheckBox" form="form" id="rcmcomposereceipt" tabindex="4" /> <roundcube:label name="returnreceipt" /></label>
</span>
<roundcube:endif />
<roundcube:if condition="config:smtp_server != '' and !in_array('dsn_default', (array)config:dont_override)" />
<roundcube:if condition="!in_array('dsn_default', (array)config:dont_override)" />
<span class="composeoption">
<label><roundcube:object name="dsnCheckBox" form="form" id="rcmcomposedsn" tabindex="4" /> <roundcube:label name="dsn" /></label>
</span>
Expand Down

0 comments on commit ee895a2

Please sign in to comment.