function SendMessage($ID, $timeout=0, $maxcount=0, $check_charset=false)
{
global $DB, $APPLICATION;
$eol = BitrixMainMailMail::getMailEol();
$ID = intval($ID);
$timeout = intval($timeout);
$start_time = getmicrotime();
@set_time_limit(0);
$this->LAST_ERROR = "";
$post = $this->GetByID($ID);
if(!($post_arr = $post->Fetch()))
{
$this->LAST_ERROR .= GetMessage("class_post_err_notfound");
return false;
}
if($post_arr["STATUS"] != "P")
{
$this->LAST_ERROR .= GetMessage("class_post_err_status")."
";
return false;
}
if(
$check_charset
&& ($post_arr["MSG_CHARSET"] <> '')
&& (mb_strtoupper($post_arr["MSG_CHARSET"]) != mb_strtoupper(LANG_CHARSET))
)
{
return "CONTINUE";
}
if(CPosting::Lock($ID)===false)
{
if($e = $APPLICATION->GetException())
{
$this->LAST_ERROR .= GetMessage("class_post_err_lock")."
".$e->GetString();
if(mb_strpos($this->LAST_ERROR, "PLS-00201") !== false && mb_strpos($this->LAST_ERROR, "'DBMS_LOCK'") !== false)
$this->LAST_ERROR .= "
".GetMessage("class_post_err_lock_advice");
$APPLICATION->ResetException();
return false;
}
else
{
return "CONTINUE";
}
}
if($post_arr["VERSION"] <> '2')
{
if(is_string($post_arr["BCC_TO_SEND"]) && $post_arr["BCC_TO_SEND"] <> '')
{
$a = explode(",", $post_arr["BCC_TO_SEND"]);
foreach($a as $e)
$DB->Query("INSERT INTO b_posting_email (POSTING_ID, STATUS, EMAIL) VALUES (".$ID.", 'Y', '".$DB->ForSQL($e)."')");
}
if(is_string($post_arr["ERROR_EMAIL"]) && $post_arr["ERROR_EMAIL"] <> '')
{
$a = explode(",", $post_arr["ERROR_EMAIL"]);
foreach($a as $e)
$DB->Query("INSERT INTO b_posting_email (POSTING_ID, STATUS, EMAIL) VALUES (".$ID.", 'E', '".$DB->ForSQL($e)."')");
}
if(is_string($post_arr["SENT_BCC"]) && $post_arr["SENT_BCC"] <> '')
{
$a = explode(",", $post_arr["SENT_BCC"]);
foreach($a as $e)
$DB->Query("INSERT INTO b_posting_email (POSTING_ID, STATUS, EMAIL) VALUES (".$ID.", 'N', '".$DB->ForSQL($e)."')");
}
$DB->Query("UPDATE b_posting SET VERSION='2', BCC_TO_SEND=null, ERROR_EMAIL=null, SENT_BCC=null WHERE ID=".$ID);
}
$tools = new CMailTools;
//MIME with attachments
if($post_arr["BODY_TYPE"]=="html" && COption::GetOptionString("subscribe", "attach_images")=="Y")
{
$post_arr["BODY"] = $tools->ReplaceImages($post_arr["BODY"]);
}
if($post_arr["CHARSET"] <> '')
{
$from_charset = $post_arr["MSG_CHARSET"]? $post_arr["MSG_CHARSET"]: SITE_CHARSET;
$post_arr["BODY"] = $APPLICATION->ConvertCharset($post_arr["BODY"], $from_charset, $post_arr["CHARSET"]);
$post_arr["SUBJECT"] = $APPLICATION->ConvertCharset($post_arr["SUBJECT"], $from_charset, $post_arr["CHARSET"]);
$post_arr["FROM_FIELD"] = $APPLICATION->ConvertCharset($post_arr["FROM_FIELD"], $from_charset, $post_arr["CHARSET"]);
}
//Preparing message header, text, subject
$sBody = str_replace("rn", "n", $post_arr["BODY"]);
$sBody = implode(
"n",
array_filter(
preg_split("/(.{512}[^ ]*[ ])/", $sBody." ", -1, PREG_SPLIT_DELIM_CAPTURE)
)
); //Some MTA has 4K limit for fgets function. So we have to split the message body.
if(COption::GetOptionString("main", "CONVERT_UNIX_NEWLINE_2_WINDOWS", "N") == "Y")
$sBody = str_replace("n", "rn", $sBody);
if(COption::GetOptionString("subscribe", "allow_8bit_chars") <> "Y")
{
$sSubject = CMailTools::EncodeSubject($post_arr["SUBJECT"], $post_arr["CHARSET"]);
$sFrom = CMailTools::EncodeHeaderFrom($post_arr["FROM_FIELD"], $post_arr["CHARSET"]);
}
else
{
$sSubject = $post_arr["SUBJECT"];
$sFrom = $post_arr["FROM_FIELD"];
}
if($post_arr["BODY_TYPE"] == "html")
{
//URN2URI
$tmpTools = new CMailTools;
$sBody = $tmpTools->ReplaceHrefs($sBody);
}
$bHasAttachments = false;
$sHeader = "";
$sBoundary = "";
if(count($tools->aMatches) > 0)
{
$bHasAttachments = true;
$sBoundary = "----------".uniqid("");
$sHeader =
'From: '.$sFrom.$eol.
'X-Bitrix-Posting: '.$post_arr["ID"].$eol.
'MIME-Version: 1.0'.$eol.
'Content-Type: multipart/mixed; boundary="'.$sBoundary.'"'.$eol.
'Content-Transfer-Encoding: 8bit';
$sBody =
"--".$sBoundary.$eol.
"Content-Type: ".($post_arr["BODY_TYPE"]=="html"? "text/html":"text/plain").($post_arr["CHARSET"]<>""? "; charset=".$post_arr["CHARSET"]:"").$eol.
"Content-Transfer-Encoding: 8bit".$eol.$eol.
$sBody.$eol;
foreach($tools->aMatches as $attachment)
{
if($post_arr["CHARSET"] <> '')
{
$from_charset = $post_arr["MSG_CHARSET"]? $post_arr["MSG_CHARSET"]: SITE_CHARSET;
$attachment["DEST"] = $APPLICATION->ConvertCharset($attachment["DEST"], $from_charset, $post_arr["CHARSET"]);
}
if(COption::GetOptionString("subscribe", "allow_8bit_chars") <> "Y")
$name = CMailTools::EncodeSubject($attachment["DEST"], $post_arr["CHARSET"]);
else
$name = $attachment["DEST"];
$sBody .=
$eol."--".$sBoundary.$eol.
"Content-Type: ".$attachment["CONTENT_TYPE"]."; name="".$name.""".$eol.
"Content-Transfer-Encoding: base64".$eol.
"Content-ID: <".$attachment["ID"].">".$eol.$eol.
chunk_split(
base64_encode(
file_get_contents($attachment["PATH"])
), 72, $eol
);
}
}
$arFiles = array();
$maxFileSize = intval(COption::GetOptionInt("subscribe", "max_file_size"));
$rsFile = CPosting::GetFileList($ID);
while($arFile = $rsFile->Fetch())
{
if (
$maxFileSize == 0
|| $arFile["FILE_SIZE"] <= $maxFileSize
)
$arFiles[] = $arFile;
}
if(!empty($arFiles))
{
if(!$bHasAttachments)
{
$bHasAttachments = true;
$sBoundary = "----------".uniqid("");
$sHeader =
"From: ".$sFrom.$eol.
'X-Bitrix-Posting: '.$post_arr["ID"].$eol.
"MIME-Version: 1.0".$eol.
"Content-Type: multipart/mixed; boundary="".$sBoundary.""".$eol.
"Content-Transfer-Encoding: 8bit";
$sBody =
"--".$sBoundary.$eol.
"Content-Type: ".($post_arr["BODY_TYPE"]=="html"? "text/html":"text/plain").($post_arr["CHARSET"]<>""? "; charset=".$post_arr["CHARSET"]:"").$eol.
"Content-Transfer-Encoding: 8bit".$eol.$eol.
$sBody.$eol;
}
foreach ($arFiles as $arFile)
{
if($post_arr["CHARSET"] <> '')
{
$from_charset = $post_arr["MSG_CHARSET"]? $post_arr["MSG_CHARSET"]: SITE_CHARSET;
$file_name = $APPLICATION->ConvertCharset($arFile["ORIGINAL_NAME"], $from_charset, $post_arr["CHARSET"]);
}
else
{
$file_name = $arFile["ORIGINAL_NAME"];
}
$sBody .=
$eol."--".$sBoundary.$eol.
"Content-Type: ".$arFile["CONTENT_TYPE"]."; name="".$file_name.""".$eol.
"Content-Transfer-Encoding: base64".$eol.
"Content-Disposition: attachment; filename="".CMailTools::EncodeHeaderFrom($file_name, $post_arr["CHARSET"]).""".$eol.$eol;
$arTempFile = CFile::MakeFileArray($arFile["ID"]);
$sBody .= chunk_split(
base64_encode(
file_get_contents($arTempFile["tmp_name"])
),
72,
$eol
);
}
}
if($bHasAttachments)
{
$sBody .= $eol."--".$sBoundary."--".$eol;
}
else
{
//plain message without MIME
$sHeader =
"From: ".$sFrom.$eol.
'X-Bitrix-Posting: '.$post_arr["ID"].$eol.
"MIME-Version: 1.0".$eol.
"Content-Type: ".($post_arr["BODY_TYPE"]=="html"? "text/html":"text/plain").($post_arr["CHARSET"]<>""? "; charset=".$post_arr["CHARSET"]:"").$eol.
"Content-Transfer-Encoding: 8bit";
}
$mail_additional_parameters = trim(COption::GetOptionString("subscribe", "mail_additional_parameters"));
$context = new MailContext();
$context->setCategory(MailContext::CAT_EXTERNAL);
$context->setPriority(MailContext::PRIORITY_LOW);
if($post_arr["DIRECT_SEND"] == "Y")
{
//personal delivery
$arEvents = GetModuleEvents("subscribe", "BeforePostingSendMail", true);
$rsEmails = $DB->Query($DB->TopSql("
SELECT *
FROM b_posting_email
WHERE POSTING_ID = ".$ID." AND STATUS='Y'
", $maxcount));
while($arEmail = $rsEmails->Fetch())
{
//Event part
$arFields = array(
"POSTING_ID" => $ID,
"EMAIL" => $arEmail["EMAIL"],
"SUBJECT" => $sSubject,
"BODY" => $sBody,
"HEADER" => $sHeader,
"EMAIL_EX" => $arEmail,
);
foreach($arEvents as $arEvent)
$arFields = ExecuteModuleEventEx($arEvent, array($arFields));
//Sending
if(is_array($arFields))
{
$to = CMailTools::EncodeHeaderFrom($arFields["EMAIL"], $post_arr["CHARSET"]);
$result = bxmail($to, $arFields["SUBJECT"], $arFields["BODY"], $arFields["HEADER"], $mail_additional_parameters, $context);
}
else
{
$result = $arFields !== false;
}
//Result check and iteration
if($result)
$DB->Query("UPDATE b_posting_email SET STATUS='N' WHERE ID = ".$arEmail["ID"]);
else
$DB->Query("UPDATE b_posting_email SET STATUS='E' WHERE ID = ".$arEmail["ID"]);
if($timeout > 0 && getmicrotime()-$start_time >= $timeout)
break;
self::$current_emails_per_hit++;
}
}
else
{
//BCC delivery
$rsEmails = $DB->Query($DB->TopSql("
SELECT *
FROM b_posting_email
WHERE POSTING_ID = ".$ID." AND STATUS='Y'
", COption::GetOptionString("subscribe", "max_bcc_count")));
$aStep = array();
while($arEmail = $rsEmails->Fetch())
$aStep[$arEmail["ID"]] = $arEmail["EMAIL"];
if(count($aStep) > 0)
{
$BCC = implode(",", $aStep);
$sHeaderStep = $sHeader.$eol."Bcc: ".$BCC;
$result = bxmail($post_arr["TO_FIELD"], $sSubject, $sBody, $sHeaderStep, $mail_additional_parameters, $context);
if($result)
{
$DB->Query("UPDATE b_posting_email SET STATUS='N' WHERE ID in (".implode(", ", array_keys($aStep)).")");
}
else
{
$DB->Query("UPDATE b_posting_email SET STATUS='E' WHERE ID in (".implode(", ", array_keys($aStep)).")");
$this->LAST_ERROR .= GetMessage("class_post_err_mail")."
";
}
}
}
//set status and delivered and error emails
$arStatuses = $this->GetEmailStatuses($ID);
if(!array_key_exists("Y", $arStatuses))
{
$STATUS = array_key_exists("E", $arStatuses)? "E": "S";
$DATE = $DB->GetNowFunction();
}
else
{
$STATUS = "P";
$DATE = "null";
}
CPosting::UnLock($ID);
$DB->Query("UPDATE b_posting SET STATUS='".$STATUS."', DATE_SENT=".$DATE." WHERE ID=".$ID);
return ($STATUS=="P"? "CONTINUE": true);
}