Skip to content

Commit 89e31e5

Browse files
author
Marius Burkard
committed
- improved mail sending library, contributed by Timme Hosting
1 parent 9145f9d commit 89e31e5

File tree

7 files changed

+371
-51
lines changed

7 files changed

+371
-51
lines changed

helper_scripts/test_mailqueue.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
// for testing, put this file in interface/web/tools
4+
5+
require_once '../../lib/config.inc.php';
6+
require_once '../../lib/app.inc.php';
7+
8+
//* Check permissions for module
9+
$app->auth->check_module_permissions('admin');
10+
11+
$app->uses('getconf,ispcmail');
12+
$mail_config = $app->getconf->get_global_config('mail');
13+
if($mail_config['smtp_enabled'] == 'y') {
14+
$mail_config['use_smtp'] = true;
15+
$app->ispcmail->setOptions($mail_config);
16+
}
17+
18+
$to = 't.heller@timmehosting.de';
19+
$subject = 'Test von ISPConfig-Mailqueue';
20+
$text = '123'."\n\n".date(DATE_RFC822)."\n\n".'SMTP: '.$mail_config['use_smtp'];
21+
$from = 'ispconfig@thomas.timmeserver.de';
22+
$filepath = '';
23+
$filetype = 'application/pdf';
24+
$filename = '';
25+
$cc = '';
26+
$bcc = '';
27+
$from_name = 'ISPConfig';
28+
29+
$app->ispcmail->setSender($from, $from_name);
30+
$app->ispcmail->setSubject($subject);
31+
$app->ispcmail->setMailText($text);
32+
33+
if($filepath != '') {
34+
if(!file_exists($filepath)) $app->error("Mail attachement does not exist ".$filepath);
35+
$app->ispcmail->readAttachFile($filepath);
36+
}
37+
38+
if($cc != '') $app->ispcmail->setHeader('Cc', $cc);
39+
if($bcc != '') $app->ispcmail->setHeader('Bcc', $bcc);
40+
41+
$app->ispcmail->send($to);
42+
$app->ispcmail->finish();
43+
44+
echo $text;
45+

install/sql/incremental/upd_0085.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ ALTER TABLE `dns_rr` CHANGE `data` `data` TEXT NOT NULL;
1818
ALTER TABLE `web_database` CHANGE `database_quota` `database_quota` INT(11) NULL DEFAULT NULL;
1919
ALTER TABLE `web_domain` ADD `log_retention` INT NOT NULL DEFAULT '30' ;
2020
ALTER TABLE spamfilter_policy CHANGE spam_tag_level spam_tag_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_tag2_level spam_tag2_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_kill_level spam_kill_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_dsn_cutoff_level spam_dsn_cutoff_level DECIMAL(5,2) NULL DEFAULT NULL, CHANGE spam_quarantine_cutoff_level spam_quarantine_cutoff_level DECIMAL(5,2) NULL DEFAULT NULL;
21-
UPDATE `web_database` as d LEFT JOIN `web_domain` as w ON (w.domain_id = d.parent_domain_id) SET d.parent_domain_id = 0 WHERE w.domain_id IS NULL AND d.parent_domain_id != 0 AND (SELECT EXISTS(SELECT * FROM web_domain));
21+
UPDATE `web_database` as d LEFT JOIN `web_domain` as w ON (w.domain_id = d.parent_domain_id) SET d.parent_domain_id = 0 WHERE w.domain_id IS NULL AND d.parent_domain_id != 0 AND (SELECT EXISTS(SELECT * FROM web_domain));

install/sql/incremental/upd_dev_collection.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,12 @@ CREATE TABLE IF NOT EXISTS `addons` (
151151
PRIMARY KEY (`addon_id`),
152152
UNIQUE KEY `ident` (`addon_ident`)
153153
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
154+
155+
CREATE TABLE IF NOT EXISTS `sys_mailqueue` (
156+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
157+
`from` varchar(255) NOT NULL DEFAULT '',
158+
`recipients` text NOT NULL,
159+
`mail_content` mediumblob NOT NULL,
160+
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
161+
PRIMARY KEY (`id`)
162+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

install/sql/ispconfig3.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,21 @@ CREATE TABLE `sys_log` (
15851585

15861586
-- --------------------------------------------------------
15871587

1588+
--
1589+
-- Table structure for table `sys_mailqueue`
1590+
--
1591+
1592+
CREATE TABLE IF NOT EXISTS `sys_mailqueue` (
1593+
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
1594+
`from` varchar(255) NOT NULL DEFAULT '',
1595+
`recipients` text NOT NULL,
1596+
`mail_content` mediumblob NOT NULL,
1597+
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
1598+
PRIMARY KEY (`id`)
1599+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
1600+
1601+
-- --------------------------------------------------------
1602+
15881603
--
15891604
-- Table structure for table `sys_remoteaction`
15901605
--

interface/lib/classes/ispcmail.inc.php

Lines changed: 112 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -744,50 +744,35 @@ public function send($recipients) {
744744
}
745745

746746
if($this->use_smtp == true) {
747-
if(!$this->_logged_in || !$this->_smtp_conn) {
748-
$result = $this->_smtp_login();
749-
if(!$result) return false;
750-
}
751747
$bcc_cc_sent = false;
752748
foreach($recipients as $recipname => $recip) {
753-
if($this->_sent_mails >= $this->smtp_max_mails) {
754-
// close connection to smtp and reconnect
755-
$this->_sent_mails = 0;
756-
$this->_smtp_close();
757-
$result = $this->_smtp_login();
758-
if(!$result) return false;
759-
}
760-
$this->_sent_mails += 1;
749+
// Build mail headers, content etc.
750+
751+
$m_recipients = array();
752+
$m_mail_content = '';
761753

762754
$recipname = trim(str_replace('"', '', $recipname));
763755
$recip = $this->_encodeHeader($recip, $this->mail_charset);
764756
$recipname = $this->_encodeHeader($recipname, $this->mail_charset);
765757

766758
//Email From
767-
fputs($this->_smtp_conn, 'MAIL FROM: <' . $this->_mail_sender . '>' . $this->_crlf);
768-
$response = fgets($this->_smtp_conn, 515);
759+
$m_from = $this->_mail_sender;
769760

770761
//Email To
771-
fputs($this->_smtp_conn, 'RCPT TO: <' . $recip . '>' . $this->_crlf);
772-
$response = fgets($this->_smtp_conn, 515);
762+
$m_recipients[] = $recip;
773763

774764
if($bcc_cc_sent == false) {
775765
$add_recips = array();
776766
if($this->getHeader('Cc') != '') $add_recips = array_merge($add_recips, $this->_extract_names($this->getHeader('Cc')));
777767
if($this->getHeader('Bcc') != '') $add_recips = array_merge($add_recips, $this->_extract_names($this->getHeader('Bcc')));
778768
foreach($add_recips as $add_recip) {
779769
if(!$add_recip['mail']) continue;
780-
fputs($this->_smtp_conn, 'RCPT TO: <' . $this->_encodeHeader($add_recip['mail'], $this->mail_charset) . '>' . $this->_crlf);
781-
$response = fgets($this->_smtp_conn, 515);
770+
$m_recipients[] = $this->_encodeHeader($add_recip['mail'], $this->mail_charset);
782771
}
783772
unset($add_recips);
784773
$bcc_cc_sent = true;
785774
}
786775

787-
//The Email
788-
fputs($this->_smtp_conn, 'DATA' . $this->_crlf);
789-
$response = fgets($this->_smtp_conn, 515);
790-
791776
//Construct Headers
792777
if($recipname && !is_numeric($recipname)) $this->setHeader('To', $recipname . ' <' . $recip . '>');
793778
else $this->setHeader('To', $recip);
@@ -797,10 +782,32 @@ public function send($recipients) {
797782
if($this->getHeader('Cc') != '') $mail_content .= 'Cc: ' . $this->_encodeHeader($this->getHeader('Cc'), $this->mail_charset) . $this->_crlf;
798783
$mail_content .= implode($this->_crlf, $headers) . $this->_crlf . ($this->_is_signed == false ? $this->_crlf : '') . $this->body;
799784

800-
fputs($this->_smtp_conn, $mail_content . $this->_crlf . '.' . $this->_crlf);
801-
$response = fgets($this->_smtp_conn, 515);
785+
$m_mail_content = $mail_content;
786+
787+
// Attempt SMTP login:
788+
789+
if(!$this->_logged_in || !$this->_smtp_conn) {
790+
$result = $this->_smtp_login();
791+
}
792+
793+
if($this->_sent_mails >= $this->smtp_max_mails) {
794+
// close connection to smtp and reconnect
795+
$this->_sent_mails = 0;
796+
$this->_smtp_close();
797+
$result = $this->_smtp_login();
798+
}
799+
$this->_sent_mails += 1;
800+
801+
// Send mail or queue it
802+
803+
if ($result) {
804+
$this->send_smtp($m_from, $m_recipients, $m_mail_content);
805+
} else {
806+
$this->add_to_queue($m_from, $m_recipients, $m_mail_content);
807+
}
808+
809+
// hopefully message was correctly sent or queued now
802810

803-
// hopefully message was correctly sent now
804811
$result = true;
805812
}
806813
} else {
@@ -828,7 +835,87 @@ public function send($recipients) {
828835
return $result;
829836
}
830837

838+
/**
839+
* Send all mails in queue (usually called from cron)
840+
*/
841+
public function send_queue() {
842+
global $app;
843+
844+
$mails = $app->db->queryAllRecords('SELECT * FROM sys_mailqueue');
845+
846+
if (is_array($mails)) {
847+
foreach ($mails as $mail) {
848+
// Open SMTP connections if not open:
849+
850+
if(!$this->_logged_in || !$this->_smtp_conn) {
851+
$result = $this->_smtp_login();
852+
}
853+
854+
if($this->_sent_mails >= $this->smtp_max_mails) {
855+
// close connection to smtp and reconnect
856+
$this->_sent_mails = 0;
857+
$this->_smtp_close();
858+
$result = $this->_smtp_login();
859+
}
860+
$this->_sent_mails += 1;
861+
862+
if (!$result) {
863+
return false;
864+
}
865+
866+
// Send mail:
867+
868+
$id = $mail['id'];
869+
$from = $mail['from'];
870+
$recipients = explode("\n", $mail['recipients']);
871+
$mail_content = $mail['mail_content'];
872+
873+
$this->send_smtp($from, $recipients, $mail_content);
874+
875+
// Delete from queue:
876+
877+
$app->db->query('DELETE FROM sys_mailqueue WHERE id = ?', $id);
878+
}
879+
}
880+
}
881+
882+
/**
883+
* Send mail via SMTP
884+
*/
885+
private function send_smtp($from, $recipients, $mail_content) {
886+
// from:
887+
888+
fputs($this->_smtp_conn, 'MAIL FROM: <' . $from . '>' . $this->_crlf);
889+
$response = fgets($this->_smtp_conn, 515);
890+
891+
// recipients (To, Cc or Bcc):
892+
893+
foreach ($recipients as $recipient) {
894+
fputs($this->_smtp_conn, 'RCPT TO: <' . $recipient . '>' . $this->_crlf);
895+
$response = fgets($this->_smtp_conn, 515);
896+
}
897+
898+
// mail content:
831899

900+
fputs($this->_smtp_conn, 'DATA' . $this->_crlf);
901+
$response = fgets($this->_smtp_conn, 515);
902+
903+
fputs($this->_smtp_conn, $mail_content . $this->_crlf . '.' . $this->_crlf);
904+
$response = fgets($this->_smtp_conn, 515);
905+
906+
// hopefully message was correctly sent now
907+
$result = true;
908+
909+
return $result;
910+
}
911+
912+
/**
913+
* Add mail to queue for sending later
914+
*/
915+
private function add_to_queue($from, $recipients, $mail_content) {
916+
global $app;
917+
$app->db->query('INSERT INTO `sys_mailqueue` (`from`, `recipients`, `mail_content`) VALUES (?,?,?)', $from, implode("\n", $recipients), $mail_content);
918+
}
832919

833920
/**
834921
* Close mail connections
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
/*
4+
Copyright (c) 2013, Marius Cramer, pixcept KG
5+
All rights reserved.
6+
7+
Redistribution and use in source and binary forms, with or without modification,
8+
are permitted provided that the following conditions are met:
9+
10+
* Redistributions of source code must retain the above copyright notice,
11+
this list of conditions and the following disclaimer.
12+
* Redistributions in binary form must reproduce the above copyright notice,
13+
this list of conditions and the following disclaimer in the documentation
14+
and/or other materials provided with the distribution.
15+
* Neither the name of ISPConfig nor the names of its contributors
16+
may be used to endorse or promote products derived from this software without
17+
specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
class cronjob_send_sys_mailqueue extends cronjob {
32+
33+
// job schedule
34+
protected $_schedule = '* * * * *';
35+
protected $_run_at_new = true;
36+
37+
/* this function is optional if it contains no custom code */
38+
public function onPrepare() {
39+
global $app;
40+
41+
parent::onPrepare();
42+
}
43+
44+
/* this function is optional if it contains no custom code */
45+
public function onBeforeRun() {
46+
global $app;
47+
48+
return parent::onBeforeRun();
49+
}
50+
51+
public function onRunJob() {
52+
global $app, $conf;
53+
54+
$app->uses('getconf,ispcmail');
55+
56+
$mail_config = $app->getconf->get_global_config('mail');
57+
if($mail_config['smtp_enabled'] == 'y') {
58+
$mail_config['use_smtp'] = true;
59+
$app->ispcmail->setOptions($mail_config);
60+
61+
// Mail queue is supported only with SMTP...
62+
$app->ispcmail->send_queue();
63+
}
64+
65+
parent::onRunJob();
66+
}
67+
68+
/* this function is optional if it contains no custom code */
69+
public function onAfterRun() {
70+
global $app;
71+
72+
parent::onAfterRun();
73+
}
74+
75+
}
76+
77+
?>

0 commit comments

Comments
 (0)