yf_email classHigh level html emails wrapper.
| File | plugins/email/classes/yf_email.class.php |
|---|---|
| Use | _class('email') |
A site sets them in its config with $PROJECT_CONF['email']['NAME'] = ...;
| Property | Default | Description |
|---|---|---|
$ADMIN_EMAILstring |
'' |
|
$ADMIN_NAMEstring |
'' |
|
$ASYNC_SENDbool |
false |
Use queues to send emails in asynchronous mode |
$DEQUEUE_USLEEP |
500000 |
|
$EMAIL_FROMstring |
'' |
|
$FORCE_SEND |
false |
|
$MAIL_DEBUG |
false |
|
$MAIL_DEBUG_ERROR |
false |
|
$NAME_FROMstring |
'' |
|
$QUEUE_NAME |
'emails_queue' |
|
$SEND_ADMIN_COPY_TOarray |
[] |
List of emails addresses to send user-addressing email copies to |
$SEND_ALL_COPY_TOarray |
[] |
List of emails addresses to send all copies to |
$SEND_USER_COPY_TOarray |
[] |
List of emails addresses to send admin-addressing email copies to |
$SITE_NAMEstring |
'' |
|
$SITE_URLstring |
'' |
|
$SMTP_CONFIG_ALTERNATEarray |
[] |
unused: it served mail.ru / bk.ru / inbox.ru / list.ru recipients until the mail.ru switch was removed; kept so a site's config entry stays harmless, removed in 4.0 |
$SMTP_CONFIG_DEFAULT |
[] |
table_tpls | 'emails_templates' | |
table_history | 'emails_history' |
public function dequeue($extra = [])
Should be wrapped under supervisor and best run from console Example supervisor config entry for it:.
[program:yf_emails_queue]
command = php index.php --object=admin_daemon --action=emails_dequeue
directory = /var/www/default/www/admin/
autorestart = true
numprocs = 1
process_name = %(program_name)s_%(process_num)s
user = www-data
Example of php settings to ensure daemon long working
if (is_console()) {
error_reporting(E_ALL & ~E_NOTICE);
ini_set('html_errors', 0);
set_time_limit(0);
ini_set('default_socket_timeout', -1);
}
public function dequeue($extra = [])
{
queue()->listen($this->QUEUE_NAME, function ($data) use ($extra) {
$data = json_decode($data, true);
if ($data) {
if ($extra['verbose']) {
$msg = 'got item from queue; '
. ($data['history_id'] ? 'history_id: "' . $data['history_id'] . '"; ' : '')
. 'mail_to: "' . $data['to_mail'] . '"; '
. 'subj: "' . $data['subj'] . '"; '
. 'mail_from: "' . $data['from_mail'] . '"; ';
echo date('Y-m-d H:i:s') . ': ' . $msg . PHP_EOL;
}
$result = common()->send_mail($data);
if ( ! $result) {
if ($extra['verbose']) {
echo date('Y-m-d H:i:s') . ': error: ' . _class('send_mail')->_last_error_message . PHP_EOL;
if (strlen($data['html']) > 500) {
$data['html'] = substr($data['html'], 0, 500) . PHP_EOL . '...TRUNCATED_FOR_DEBUG...' . PHP_EOL;
}
var_dump($data);
}
} else {
if ($data['history_id']) {
db()->update_safe(self::table_history, ['status' => 1], 'id=' . (int) $data['history_id']);
}
if ($extra['verbose']) {
echo date('Y-m-d H:i:s') . ': sent ok' . PHP_EOL;
}
}
}
}, ['usleep' => $this->DEQUEUE_USLEEP]);
}
public function strip_html_tags($text)
Remove HTML tags, including invisible text such as style and script code, and embedded objects. Add line breaks around block-level tags to prevent word joining after tag removal.
source article: http://nadeausoftware.com/articles/2007/09/php_tip_how_strip_html_tags_web_page
_ hooks and helpers; not routable as page actionspublic function __call($name, $args)
Catch missing method call.
public function __call($name, $args)
{
return main()->extend_call($this, $name, $args);
}
public function _css_to_inline_styles($html = '', $extra = [])
public function _css_to_inline_styles($html = '', $extra = [])
{
if ( ! strlen($html) || false === strpos($html, '<')/* || false === strpos($html, 'style=')*/) {
return $html;
}
$need_raw = false;
if (false === strpos($html, '<html') && false === strpos($html, '<body')) {
$need_raw = true;
$html = '<!DOCTYPE html><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta charset="utf-8"></head><body>' . $html . '</body></html>';
}
require_php_lib('css_to_inline_styles');
$cti = new \TijsVerkoyen\CssToInlineStyles\CssToInlineStyles($html);
$cti->setEncoding('UTF-8');
$cti->setUseInlineStylesBlock();
$result = $cti->convert();
$result = preg_replace('~<style[^>]*?>.+?</style>~ims', '', $result);
$result = preg_replace('~<script[^>]*?>.+?</script>~ims', '', $result);
if ($need_raw) {
preg_match('|<body.*>(.*)</body>|isU', $result, $matches);
$result = ($matches[1] ?? null) ?: $result;
}
return $result;
}
public function _get_email_text($replace = [], $extra = [])
public function _get_email_text($replace = [], $extra = [])
{
$a = null;
if ($extra['tpl_name']) {
$lang = ($extra['locale'] ?? null) ?: conf('language');
$a = db()->from(self::table_tpls)->where('name', $extra['tpl_name'])->where('locale', $lang)->get();
if ( ! $a) {
$a = db()->from(self::table_tpls)->where('name', $extra['tpl_name'])->get();
}
}
if ($extra['subject']) {
$a['subject'] = $extra['subject'];
}
$body = ($a['text'] ?? null) ?: $extra['body'];
if ($a['parent_id']) {
$parent = db()->from(self::table_tpls)->whereid($a['parent_id'])->where('locale', $a['locale'])->get();
if ( ! $parent) {
$parent = db()->from(self::table_tpls)->whereid($a['parent_id'])->get();
}
if ($parent) {
$body = tpl()->parse_string($parent['text'], [
'main_content' => $body,
]);
}
}
$subject = strip_tags($a['subject']);
if (empty($subject) && empty($body)) {
return false;
}
$replace = (array) $replace + [
'site_name' => $this->SITE_NAME,
'site_url' => $this->SITE_URL,
'unsubscribe_url' => url_user('/unsubscribe/show/' . $extra['tpl_name'] . '-' . time()),
];
return [
tpl()->parse_string($subject, $replace),
tpl()->parse_string($body, $replace),
];
}
public function _init()
public function _init()
{
$this->ADMIN_EMAIL = defined('SITE_ADMIN_EMAIL') && strlen(SITE_ADMIN_EMAIL) ? SITE_ADMIN_EMAIL : 'support@' . ($_SERVER['HTTP_HOST'] ?? null);
$this->ADMIN_NAME = defined('SITE_ADMIN_NAME') && strlen(SITE_ADMIN_NAME) ? SITE_ADMIN_NAME : SITE_ADVERT_TITLE . ' support';
$this->EMAIL_FROM = SITE_ADMIN_EMAIL;
$this->NAME_FROM = SITE_ADVERT_NAME;
$this->SITE_NAME = SITE_ADVERT_NAME;
$this->SITE_URL = SITE_ADVERT_URL;
}
public function _send_copies($params = [])
Send copies, mostly for debug and more control on what is going on.
public function _send_copies($params = [])
{
$email_to = null;
if ( ! $params) {
return false;
}
$copy_to = [];
foreach ((array) $this->SEND_ALL_COPY_TO as $mail_to) {
$copy_to[$mail_to] = $mail_to;
}
if ($email_to === $this->ADMIN_EMAIL) {
foreach ((array) $this->SEND_ADMIN_COPY_TO as $mail_to) {
$copy_to[$mail_to] = $mail_to;
}
} else {
foreach ((array) $this->SEND_USER_COPY_TO as $mail_to) {
$copy_to[$mail_to] = $mail_to;
}
}
$orig_to_mail = strtolower(trim($params['to_mail']));
$orig_subj = $params['subj'];
$params['subj'] = '[AUTO-COPY] ' . $params['subj'];
foreach ((array) $copy_to as $mail_to) {
$mail_to = trim($mail_to);
if ( ! $mail_to || strtolower($mail_to) == $orig_to_mail) {
continue;
}
$params['to_mail'] = $mail_to;
if ($this->ASYNC_SEND) {
queue()->add($this->QUEUE_NAME, json_encode($params));
} else {
common()->send_mail((array) $params);
}
}
return true;
}
public function _send_email_safe($email_to, $name_to, $template_name, $data = [], $old_param1 = null, $override = [])
send_email_from_admin.
public function _send_email_safe($email_to, $name_to, $template_name, $data = [], $old_param1 = null, $override = [])
{
$is_test = (defined('TEST_MODE') && TEST_MODE)
&& empty($override['force_send'])
&& empty($this->FORCE_SEND);
if ($is_test) {
common()->message_error('Test mode enabled. Email real sending is disabled');
return false;
}
if (empty($email_to)) {
return false;
}
if (empty($name_to)) {
$name_to = $email_to;
}
list($subject, $html) = $this->_get_email_text($data, ['tpl_name' => $template_name]);
if ($override['subject']) {
$subject = $override['subject'];
}
db()->insert_safe(self::table_history, [
'email_to' => $email_to,
'name_to' => $name_to,
'subject' => $subject,
'text' => $html,
'date' => ($_SERVER['REQUEST_TIME'] ?? null),
]);
if ( ! $html) {
if ($this->MAIL_DEBUG_ERROR) {
trigger_error('Email body is empty', E_USER_WARNING);
}
return null;
}
$email_id = db()->insert_id();
$params = [
'from_mail' => $this->EMAIL_FROM,
'from_name' => $this->NAME_FROM,
'to_mail' => $email_to,
'to_name' => $name_to,
'subj' => $subject,
'text' => $this->_text_from_html($html),
'html' => $this->_css_to_inline_styles($html),
'smtp' => $this->SMTP_CONFIG_DEFAULT,
];
if ($this->ASYNC_SEND) {
$result = queue()->add($this->QUEUE_NAME, json_encode($params + ['history_id' => $email_id]));
$this->_send_copies($params);
} else {
$result = common()->send_mail((array) $params);
if ( ! $result) {
if ($this->MAIL_DEBUG_ERROR) {
trigger_error('Email not sent', E_USER_WARNING);
}
} else {
db()->update_safe(self::table_history, ['status' => 1], 'id=' . (int) $email_id);
$this->_send_copies($params);
}
}
return $result;
}
public function _send_email_to_user($user_id, $template_name, $data = [], $instant_send = true, $require_verified_email = false, $is_wall_update = true, $template_group = '')
public function _send_email_to_user($user_id, $template_name, $data = [], $instant_send = true, $require_verified_email = false, $is_wall_update = true, $template_group = '')
{
$instant_send = false;
$user_data = db()->from('user')->whereid($user_id)->get();
if (empty($user_data)) {
return false;
}
if (empty($data['name'])) {
$data['name'] = $user_data['name'];
}
if (substr($user_data['email'], 0, 6) == 'oauth.') {
// no support for oauth-based auths
return false;
}
if ($require_verified_email && ($user_data['email'] != $user_data['email_validated'])) {
return false;
}
if ($is_wall_update) {
return false;
}
if ($is_wall_update && $template_group != '') {
$a = [];
if ($user_data['email_wall_updates_config'] != '') {
$data_config = json_decode($user_data['email_wall_updates_config'], true);
foreach ($data_config as $v) {
$a[$v] = $v;
}
if (empty($a[$template_group])) {
return false;
}
} else {
return false;
}
}
return $this->_send_email_safe($user_data['email'], $user_data['name'], $template_name, $data, $instant_send);
}
public function _send_to_default_admin($extra = [])
public function _send_to_default_admin($extra = [])
{
$params = [
'from_mail' => $this->EMAIL_FROM,
'from_name' => $this->NAME_FROM,
'to_mail' => $this->ADMIN_EMAIL,
'to_name' => $this->ADMIN_NAME,
'subj' => $extra['subject'],
'text' => $this->_text_from_html($extra['html']),
'html' => $this->_css_to_inline_styles($extra['html']),
'smtp' => $this->SMTP_CONFIG_DEFAULT,
];
if ($this->ASYNC_SEND) {
$result = queue()->add($this->QUEUE_NAME, json_encode($params));
} else {
$result = common()->send_mail((array) $params);
}
$this->_send_copies($params);
return $result;
}
public function _text_from_html($html = '')
public function _text_from_html($html = '')
{
if ( ! strlen($html)) {
return $html;
}
$text = trim($html);
$text = trim($this->strip_html_tags($text));
$text = str_replace("\t", ' ', $text);
$text = preg_replace("~[\r\n][ ]+~m", PHP_EOL, $text);
$text = preg_replace("~[\r\n]{2,}~m", PHP_EOL, $text);
return $text;
}