2 /***************************************************************
5 * (c) 1999-2004 Kasper Skaarhoj (kasperYYYY@typo3.com)
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
28 * Class, doing the sending of Direct-mails, eg. through a cron-job
29 * Belongs to/See "direct_mail" extension.
33 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
36 * [CLASS/FUNCTION INDEX of SCRIPT]
40 * 86: class t3lib_dmailer extends t3lib_htmlmail
41 * 97: function dmailer_prepare($row)
42 * 147: function dmailer_sendAdvanced($recipRow,$tableNameChar)
43 * 218: function dmailer_sendSimple($addressList)
44 * 241: function dmailer_getBoundaryParts($cArray,$userCategories)
45 * 263: function dmailer_masssend($query_info,$table,$mid)
46 * 299: function dmailer_masssend_list($query_info,$mid)
47 * 360: function shipOfMail($mid,$recipRow,$tKey)
48 * 377: function convertFields($recipRow)
49 * 392: function dmailer_setBeginEnd($mid,$key)
50 * 416: function dmailer_howManySendMails($mid,$rtbl='')
51 * 430: function dmailer_isSend($mid,$rid,$rtbl)
52 * 442: function dmailer_getSentMails($mid,$rtbl)
53 * 461: function dmailer_addToMailLog($mid,$rid,$size,$parsetime,$html)
54 * 483: function runcron()
57 * (This index is automatically created/updated by the extension "extdeveval")
65 * SETTING UP a cron job on a UNIX box for distribution:
72 * Then enter this line follow by a line-break:
74 * * * * * /www/[path-to-your-typo3-site]/typo3/mod/web/dmail/dmailerd.phpcron
76 * Every minute the cronjob checks if there are mails in the queue.
77 * If there are mails, 100 is sent at a time per job.
80 * Class, doing the sending of Direct-mails, eg. through a cron-job
82 * @author Kasper Skaarhoj <kasperYYYY@typo3.com>
86 class t3lib_dmailer
extends t3lib_htmlmail
{
87 var $sendPerCycle =50;
88 var $logArray =array();
89 var $massend_id_lists = array();
94 * @param [type] $row: ...
97 function dmailer_prepare($row) {
98 $sys_dmail_uid = $row['uid'];
99 if($row["encoding"] == "base64") {
102 $this->theParts
= unserialize($row['mailContent']);
103 $this->messageid
= $this->theParts
['messageid'];
104 $this->subject
= $row['subject'];
105 $this->from_email
= $row['from_email'];
106 $this->from_name
= ($row['from_name']) ?
$row['from_name'] : '';
107 $this->replyto_email
= ($row['replyto_email']) ?
$row['replyto_email'] : '';
108 $this->replyto_name
= ($row['replyto_name']) ?
$row['replyto_name'] : '';
109 $this->organisation
= ($row['organisation']) ?
$row['organisation'] : '';
110 $this->priority
= t3lib_div
::intInRange($row['priority'],1,5);
111 $this->mailer
= 'TYPO3 Direct Mail module';
113 $this->dmailer
['sectionBoundary'] = '<!--DMAILER_SECTION_BOUNDARY';
114 $this->dmailer
['html_content'] = base64_decode($this->theParts
['html']['content']);
115 $this->dmailer
['plain_content'] = base64_decode($this->theParts
['plain']['content']);
116 $this->dmailer
['messageID'] = $this->messageid
;
117 $this->dmailer
['sys_dmail_uid'] = $sys_dmail_uid;
118 $this->dmailer
['sys_dmail_rec'] = $row;
120 $this->dmailer
['boundaryParts_html'] = explode($this->dmailer
['sectionBoundary'], '_END-->'.$this->dmailer
['html_content']);
121 while(list($bKey,$bContent)=each($this->dmailer
['boundaryParts_html'])) {
122 $this->dmailer
['boundaryParts_html'][$bKey] = explode('-->',$bContent,2);
123 // Now, analyzing which media files are used in this part of the mail:
124 $mediaParts = explode('cid:part',$this->dmailer
['boundaryParts_html'][$bKey][1]);
127 while(list(,$part)=each($mediaParts)) {
128 $this->dmailer
['boundaryParts_html'][$bKey]['mediaList'].=','.strtok($part,'.');
131 $this->dmailer
['boundaryParts_plain'] = explode($this->dmailer
['sectionBoundary'], '_END-->'.$this->dmailer
['plain_content']);
132 while(list($bKey,$bContent)=each($this->dmailer
['boundaryParts_plain'])) {
133 $this->dmailer
['boundaryParts_plain'][$bKey] = explode('-->',$bContent,2);
136 $this->flag_html
= $this->theParts
['html']['content'] ?
1 : 0;
137 $this->flag_plain
= $this->theParts
['plain']['content'] ?
1 : 0;
141 * [Describe function...]
143 * @param [type] $recipRow: ...
144 * @param [type] $tableNameChar: ...
147 function dmailer_sendAdvanced($recipRow,$tableNameChar) {
149 if ($recipRow['email']) {
150 $midRidId = 'MID'.$this->dmailer
['sys_dmail_uid'].'_'.$tableNameChar.$recipRow['uid'];
151 $uniqMsgId = md5(microtime()).'_'.$midRidId;
152 $rowFieldsArray = explode(',', 'uid,name,title,email,phone,www,address,company,city,zip,country,fax,firstname');
153 $uppercaseFieldsArray = explode(',', 'name,firstname');
154 $authCode = t3lib_div
::stdAuthCode($recipRow['uid']);
156 if ($this->flag_html
&& $recipRow['module_sys_dmail_html']) {
157 $tempContent_HTML = $this->dmailer_getBoundaryParts($this->dmailer
['boundaryParts_html'],$recipRow['module_sys_dmail_category']);
158 reset($rowFieldsArray);
159 while(list(,$substField)=each($rowFieldsArray)) {
160 $tempContent_HTML = str_replace('###USER_'.$substField.'###', $recipRow[$substField], $tempContent_HTML);
162 reset($uppercaseFieldsArray);
163 while(list(,$substField)=each($uppercaseFieldsArray)) {
164 $tempContent_HTML = str_replace('###USER_'.strtoupper($substField).'###', strtoupper($recipRow[$substField]), $tempContent_HTML);
166 $tempContent_HTML = str_replace('###SYS_TABLE_NAME###', $tableNameChar, $tempContent_HTML); // Put in the tablename of the userinformation
167 $tempContent_HTML = str_replace('###SYS_MAIL_ID###', $this->dmailer
['sys_dmail_uid'], $tempContent_HTML); // Put in the uid of the mail-record
168 $tempContent_HTML = str_replace('###SYS_AUTHCODE###', $authCode, $tempContent_HTML);
169 $tempContent_HTML = str_replace($this->dmailer
['messageID'], $uniqMsgId, $tempContent_HTML); // Put in the unique message id in HTML-code
170 $this->theParts
['html']['content'] = $this->encodeMsg($tempContent_HTML);
172 } else $this->theParts
['html']['content'] = '';
175 if ($this->flag_plain
) {
176 $tempContent_Plain = $this->dmailer_getBoundaryParts($this->dmailer
['boundaryParts_plain'],$recipRow['module_sys_dmail_category']);
177 reset($rowFieldsArray);
178 while(list(,$substField)=each($rowFieldsArray)) {
179 $tempContent_Plain = str_replace('###USER_'.$substField.'###', $recipRow[$substField], $tempContent_Plain);
181 reset($uppercaseFieldsArray);
182 while(list(,$substField)=each($uppercaseFieldsArray)) {
183 $tempContent_Plain = str_replace('###USER_'.strtoupper($substField).'###', strtoupper($recipRow[$substField]), $tempContent_Plain);
185 $tempContent_Plain = str_replace('###SYS_TABLE_NAME###', $tableNameChar, $tempContent_Plain); // Put in the tablename of the userinformation
186 $tempContent_Plain = str_replace('###SYS_MAIL_ID###', $this->dmailer
['sys_dmail_uid'], $tempContent_Plain); // Put in the uid of the mail-record
187 $tempContent_Plain = str_replace('###SYS_AUTHCODE###', $authCode, $tempContent_Plain);
189 if (trim($this->dmailer
['sys_dmail_rec']['long_link_rdct_url'])) {
190 $tempContent_Plain = t3lib_div
::substUrlsInPlainText($tempContent_Plain,$this->dmailer
['sys_dmail_rec']['long_link_mode']?
'all':'76',trim($this->dmailer
['sys_dmail_rec']['long_link_rdct_url']));
193 $this->theParts
['plain']['content'] = $this->encodeMsg($tempContent_Plain);
195 } else $this->theParts
['plain']['content'] = '';
198 $this->Xid
= $midRidId.'-'.md5($midRidId);
199 $this->returnPath
= str_replace('###XID###',$midRidId,$this->dmailer
['sys_dmail_rec']['return_path']);
204 $this->setRecipient($recipRow['email']);
206 $this->message
= str_replace($this->dmailer
['messageID'], $uniqMsgId, $this->message
); // Put in the unique message id in whole message body
207 $this->sendtheMail();
213 * [Describe function...]
215 * @param [type] $addressList: ...
218 function dmailer_sendSimple($addressList) {
220 if ($this->theParts
['html']['content']) {
221 $this->theParts
['html']['content'] = $this->encodeMsg($this->dmailer_getBoundaryParts($this->dmailer
['boundaryParts_html'],-1));
222 } else $this->theParts
['html']['content'] = '';
223 if ($this->theParts
['plain']['content']) {
224 $this->theParts
['plain']['content'] = $this->encodeMsg($this->dmailer_getBoundaryParts($this->dmailer
['boundaryParts_plain'],-1));
225 } else $this->theParts
['plain']['content'] = '';
229 $this->setRecipient($addressList);
230 $this->sendtheMail();
235 * [Describe function...]
237 * @param [type] $cArray: ...
238 * @param [type] $userCategories: ...
241 function dmailer_getBoundaryParts($cArray,$userCategories) {
242 $userCategories = intval($userCategories);
245 while(list(,$cP)=each($cArray)) {
246 $key=substr($cP[0],1);
247 if ($key=='END' ||
!$key ||
$userCategories<0 ||
(intval($key) & $userCategories)>0) {
249 $this->mediaList
.=$cP['mediaList'];
256 * [Describe function...]
258 * @param [type] $query_info: ...
259 * @param [type] $table: ...
260 * @param [type] $mid: ...
263 function dmailer_masssend($query_info,$table,$mid) {
264 $enableFields['tt_address']='NOT tt_address.deleted AND NOT tt_address.hidden';
265 $enableFields['fe_users']='NOT fe_users.deleted AND NOT fe_users.disable';
266 $tKey = substr($table,0,1);
267 $begin=intval($this->dmailer_howManySendMails($mid,$tKey));
268 if ($query_info[$table]) {
269 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($table.'.*', $table, $enableFields[$table].' AND ('.$query_info[$table].')', '', 'tstamp DESC', intval($begin).','.$this->sendPerCycle
); // This way, we select newest edited records first. So if any record is added or changed in between, it'll end on top and do no harm
270 if ($GLOBALS['TYPO3_DB']->sql_error()) {
271 die ($GLOBALS['TYPO3_DB']->sql_error());
273 $numRows = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
275 while($recipRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
276 if (!$this->dmailer_isSend($mid,$recipRow['uid'],$tKey)) {
277 $pt = t3lib_div
::milliseconds();
278 if ($recipRow['telephone']) $recipRow['phone'] = $recipRow['telephone']; // Compensation for the fact that fe_users has the field, 'telephone' instead of 'phone'
279 $recipRow['firstname']=strtok(trim($recipRow['name']),' ');
281 $rC = $this->dmailer_sendAdvanced($recipRow,$tKey);
282 $this->dmailer_addToMailLog($mid,$tKey.'_'.$recipRow['uid'],strlen($this->message
),t3lib_div
::milliseconds()-$pt,$rC);
286 $this->logArray
[]='Sending '.$cc.' mails to table '.$table;
287 if ($numRows < $this->sendPerCycle
) return true;
293 * [Describe function...]
295 * @param [type] $query_info: ...
296 * @param [type] $mid: ...
299 function dmailer_masssend_list($query_info,$mid) {
300 $enableFields['tt_address']='NOT tt_address.deleted AND NOT tt_address.hidden';
301 $enableFields['fe_users']='NOT fe_users.deleted AND NOT fe_users.disable';
305 if (is_array($query_info['id_lists'])) {
306 reset($query_info['id_lists']);
307 while(list($table,$listArr)=each($query_info['id_lists'])) {
308 if (is_array($listArr)) {
311 if ($table=='tt_address' ||
$table=='fe_users') {
312 $tKey = substr($table,0,1);
313 } elseif ($table=='PLAINLIST') {
318 $sendIds=$this->dmailer_getSentMails($mid,$tKey);
319 if ($table=='PLAINLIST') {
320 $sendIdsArr=explode(',',$sendIds);
322 while(list($kval,$recipRow)=each($listArr)) {
324 if (!in_array($kval,$sendIdsArr)) {
325 if ($c>=$this->sendPerCycle
) {$returnVal = false; break;} // We are NOT finished!
326 $recipRow['uid']=$kval;
327 $this->shipOfMail($mid,$recipRow,$tKey);
333 $idList = implode(',',$listArr);
335 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($table.'.*', $table, 'uid IN ('.$idList.') AND uid NOT IN ('.($sendIds?
$sendIds:0).') AND '.($enableFields[$table]?
$enableFields[$table]:'1=1'), '', '', $this->sendPerCycle+
1);
336 if ($GLOBALS['TYPO3_DB']->sql_error()) {die ($GLOBALS['TYPO3_DB']->sql_error());}
337 while($recipRow = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
338 if ($c>=$this->sendPerCycle
) {$returnVal = false; break;} // We are NOT finished!
339 $this->shipOfMail($mid,$recipRow,$tKey);
345 $this->logArray
[]='Sending '.$ct.' mails to table '.$table;
353 * [Describe function...]
355 * @param [type] $mid: ...
356 * @param [type] $recipRow: ...
357 * @param [type] $tKey: ...
360 function shipOfMail($mid,$recipRow,$tKey) {
361 if (!$this->dmailer_isSend($mid,$recipRow['uid'],$tKey)) {
362 $pt = t3lib_div
::milliseconds();
363 $recipRow=$this->convertFields($recipRow);
365 // debug('->'.$recipRow['uid'],1);
366 $rC=$this->dmailer_sendAdvanced($recipRow,$tKey);
367 $this->dmailer_addToMailLog($mid,$tKey.'_'.$recipRow['uid'],strlen($this->message
),t3lib_div
::milliseconds()-$pt,$rC);
372 * [Describe function...]
374 * @param [type] $recipRow: ...
377 function convertFields($recipRow) {
378 if ($recipRow['telephone']) $recipRow['phone'] = $recipRow['telephone']; // Compensation for the fact that fe_users has the field, 'telephone' instead of 'phone'
379 $recipRow['firstname']=trim(strtok(trim($recipRow['name']),' '));
380 if (strlen($recipRow['firstname'])<2 ||
ereg('[^[:alnum:]]$',$recipRow['firstname'])) $recipRow['firstname']=$recipRow['name']; // Firstname must be more that 1 character
381 if (!trim($recipRow['firstname'])) $recipRow['firstname']=$recipRow['email'];
386 * [Describe function...]
388 * @param [type] $mid: ...
389 * @param [type] $key: ...
392 function dmailer_setBeginEnd($mid,$key) {
393 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_dmail', 'uid='.intval($mid), array('scheduled_'.$key => time()));
397 $subject = 'DMAILER mid:'.$mid.' JOB BEGIN';
398 $message = ': '.date('d-m-y h:i:s');
401 $subject = 'DMAILER mid:'.$mid.' JOB END';
402 $message = ': '.date('d-m-y h:i:s');
405 $this->logArray
[] = $subject.': '.$message;
406 mail($this->from_email
, $subject, $message);
410 * [Describe function...]
412 * @param [type] $mid: ...
413 * @param [type] $rtbl: ...
416 function dmailer_howManySendMails($mid,$rtbl='') {
417 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('count(*)', 'sys_dmail_maillog', 'mid='.intval($mid).' AND response_type=0'.($rtbl ?
' AND rtbl="'.$GLOBALS['TYPO3_DB']->quoteStr($rtbl, 'sys_dmail_maillog').'"' : ''));
418 $row = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
423 * [Describe function...]
425 * @param [type] $mid: ...
426 * @param [type] $rid: ...
427 * @param [type] $rtbl: ...
430 function dmailer_isSend($mid,$rid,$rtbl) {
431 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'sys_dmail_maillog', 'rid='.intval($rid).' AND rtbl="'.$GLOBALS['TYPO3_DB']->quoteStr($rtbl, 'sys_dmail_maillog').'" AND mid='.intval($mid).' AND response_type=0');
432 return $GLOBALS['TYPO3_DB']->sql_num_rows($res);
436 * [Describe function...]
438 * @param [type] $mid: ...
439 * @param [type] $rtbl: ...
442 function dmailer_getSentMails($mid,$rtbl) {
443 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('rid', 'sys_dmail_maillog', 'mid='.intval($mid).' AND rtbl="'.$GLOBALS['TYPO3_DB']->quoteStr($rtbl, 'sys_dmail_maillog').'" AND response_type=0');
445 while($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
446 $list[] = $row['rid'];
448 return implode(',', $list);
452 * [Describe function...]
454 * @param [type] $mid: ...
455 * @param [type] $rid: ...
456 * @param [type] $size: ...
457 * @param [type] $parsetime: ...
458 * @param [type] $html: ...
461 function dmailer_addToMailLog($mid,$rid,$size,$parsetime,$html) {
462 $temp_recip = explode('_',$rid);
464 $insertFields = array(
465 'mid' => intval($mid),
466 'rtbl' => $temp_recip[0],
467 'rid' => intval($temp_recip[1]),
471 'parsetime' => $parsetime,
472 'html_sent' => intval($html)
475 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_dmail_maillog', $insertFields);
479 * [Describe function...]
484 $pt = t3lib_div
::milliseconds();
486 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_dmail', 'scheduled!=0 AND scheduled<'.time().' AND scheduled_end=0', '', 'scheduled');
487 if ($GLOBALS['TYPO3_DB']->sql_error()) {
488 die ($GLOBALS['TYPO3_DB']->sql_error());
490 $this->logArray
[]='Invoked at '.date('h:i:s d-m-Y');
492 if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
493 $this->logArray
[]='sys_dmail record '.$row['uid'].", '".$row['subject']."' processed...";
494 $this->dmailer_prepare($row);
495 $query_info=unserialize($row['query_info']);
496 if (!$row['scheduled_begin']) {$this->dmailer_setBeginEnd($row['uid'],'begin');}
498 $finished = $this->dmailer_masssend($query_info,'tt_address',$row['uid']);
500 $finished = $this->dmailer_masssend($query_info,'fe_users',$row['uid']);
502 $finished = $this->dmailer_masssend_list($query_info,$row['uid']);
504 if ($finished) {$this->dmailer_setBeginEnd($row['uid'],'end');}
506 $this->logArray
[]='Nothing to do.';
509 $parsetime=t3lib_div
::milliseconds()-$pt;
510 $this->logArray
[]='Ending, parsetime: '.$parsetime.' ms';;
515 if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['t3lib/class.t3lib_dmailer.php']) {
516 include_once($TYPO3_CONF_VARS[TYPO3_MODE
]['XCLASS']['t3lib/class.t3lib_dmailer.php']);