/** * Sends an email, wrapping PHP's mail() function. * ALL emails sent by b2evolution must be sent through this function (for consistency and for logging) * * {@link $current_locale} will be used to set the charset. * * Note: we use a single \n as line ending, though it does not comply to {@link http://www.faqs.org/rfcs/rfc2822 RFC2822}, but seems to be safer, * because some mail transfer agents replace \n by \r\n automatically. * * @todo Unit testing with "nice addresses" This gets broken over and over again. * * @param string Recipient email address. * @param string Recipient name. * @param string Subject of the mail * @param string The message text * @param string From address, being added to headers (we'll prevent injections); see {@link http://securephp.damonkohler.com/index.php/Email_Injection}. * Defaults to {@link GeneralSettings::get('notification_sender_email') } if NULL. * @param string From name. * @param array Additional headers ( headername => value ). Take care of injection! * @param integer User ID * @return boolean True if mail could be sent (not necessarily delivered!), false if not - (return value of {@link mail()}) */ function send_mail($to, $to_name, $subject, $message, $from = NULL, $from_name = NULL, $headers = array(), $user_ID = NULL) { global $servertimenow; // Stop a request from the blocked IP addresses antispam_block_ip(); global $debug, $app_name, $app_version, $current_locale, $current_charset, $evo_charset, $locales, $Debuglog, $Settings, $demo_mode, $sendmail_additional_params; // Memorize email address $to_email_address = $to; $NL = "\r\n"; if ($demo_mode) { // Debug mode restriction: Sending email in debug mode is not allowed return false; } if (!is_array($headers)) { // Make sure $headers is an array $headers = array($headers); } if (empty($from)) { $from = user_get_notification_sender($user_ID, 'email'); } if (empty($from_name)) { $from_name = user_get_notification_sender($user_ID, 'name'); } $return_path = $Settings->get('notification_return_path'); // Add real name into $from... if (!is_windows()) { // fplanque: Windows XP, Apache 1.3, PHP 4.4, MS SMTP : will not accept "nice" addresses. if (!empty($to_name)) { $to = '"' . mail_encode_header_string($to_name) . '" <' . $to . '>'; } if (!empty($from_name)) { $from = '"' . mail_encode_header_string($from_name) . '" <' . $from . '>'; } } $from = mail_sanitize_header_string($from, true); // From has to go into headers $headers['From'] = $from; if (!empty($return_path)) { // Set a return path $headers['Return-Path'] = $return_path; } // echo 'sending email to: ['.htmlspecialchars($to).'] from ['.htmlspecialchars($from).']'; $clear_subject = $subject; $subject = mail_encode_header_string($subject); $message = str_replace(array("\r\n", "\r"), $NL, $message); // Convert encoding of message (from internal encoding to the one of the message): // fp> why do we actually convert to $current_charset? // dh> I do not remember. Appears to make sense sending it unconverted in $evo_charset. // asimo> converting the message creates wrong output, no need for conversion, however this needs further investigation // $message = convert_charset( $message, $current_charset, $evo_charset ); if (!isset($headers['Content-Type'])) { // Specify charset and content-type of email $headers['Content-Type'] = 'text/plain; charset=' . $current_charset; } $headers['MIME-Version'] = '1.0'; $headers['Date'] = gmdate('r', $servertimenow); // ADDITIONAL HEADERS: $headers['X-Mailer'] = $app_name . ' ' . $app_version . ' - PHP/' . phpversion(); $ip_list = implode(',', get_ip_list()); if (!empty($ip_list)) { // Add X-Remote_Addr param only if its value is not empty $headers['X-Remote-Addr'] = $ip_list; } // COMPACT HEADERS: $headerstring = ''; reset($headers); while (list($lKey, $lValue) = each($headers)) { // Add additional headers $headerstring .= $lKey . ': ' . $lValue . $NL; } // Set an additional parameter for the return path: if (!empty($sendmail_additional_params)) { $additional_parameters = str_replace(array('$from-address$', '$return-address$'), array($from, empty($return_path) ? $from : $return_path), $sendmail_additional_params); } else { $additional_parameters = ''; } if (mail_is_blocked($to_email_address)) { // Check if the email address is blocked $Debuglog->add('Sending mail to «' . htmlspecialchars($to_email_address) . '» FAILED, because this email marked with spam or permanent errors.', 'error'); mail_log($user_ID, $to_email_address, $clear_subject, $message, $headerstring, 'blocked'); return false; } // SEND MESSAGE: if ($debug > 1) { // We agree to die for debugging... if (!mail($to, $subject, $message, $headerstring, $additional_parameters)) { mail_log($user_ID, $to_email_address, $clear_subject, $message, $headerstring, 'error'); debug_die('Sending mail from «' . htmlspecialchars($from) . '» to «' . htmlspecialchars($to) . '», Subject «' . htmlspecialchars($subject) . '» FAILED.'); } } else { // Soft debugging only.... if (!@mail($to, $subject, $message, $headerstring, $additional_parameters)) { $Debuglog->add('Sending mail from «' . htmlspecialchars($from) . '» to «' . htmlspecialchars($to) . '», Subject «' . htmlspecialchars($subject) . '» FAILED.', 'error'); mail_log($user_ID, $to_email_address, $clear_subject, $message, $headerstring, 'error'); return false; } } $Debuglog->add('Sent mail from «' . htmlspecialchars($from) . '» to «' . htmlspecialchars($to) . '», Subject «' . htmlspecialchars($subject) . '».'); mail_log($user_ID, $to_email_address, $clear_subject, $message, $headerstring, 'ok'); return true; }
/** * Send account validation email with a permanent validation link * * @param array user ids to send validation email * @param boolean true if this email is an account activation reminder, false if the account status was changed right now * @return integer the number of successfully sent emails */ function send_easy_validate_emails($user_ids, $is_reminder = true, $email_changed = false) { global $UserSettings, $servertimenow, $secure_htsrv_url; $UserCache =& get_UserCache(); if (isset($GLOBALS['messaging_Module'])) { // Get already received messages for each recepient user $already_received_messages = get_users_unread_threads($user_ids); } $cache_by_locale = array(); $email_sent = 0; foreach ($user_ids as $user_ID) { // Iterate through user ids and send account activation reminder to all user $User = $UserCache->get_by_ID($user_ID, false); if (!$User) { // user not exists continue; } if (!$User->check_status('can_be_validated')) { // User is validated or it is not allowed to be validated continue; } if ($is_reminder && !$UserSettings->get('send_activation_reminder')) { // This is an activation reminder, but user wouldn't like to receive this kind of emails continue; } if (mail_is_blocked($User->get('email'))) { // prevent trying to send an email to a blocked email address continue; } $notify_locale = $User->get('locale'); $reminder_key = $UserSettings->get('last_activation_reminder_key', $User->ID); if (empty($reminder_key) || $email_changed) { // reminder key was not generated yet, or the user email address was changed and we need a new one, to invalidate old requests $reminder_key = generate_random_key(32); $UserSettings->set('last_activation_reminder_key', $reminder_key, $User->ID); } if (!isset($cache_by_locale[$notify_locale])) { // No subject for this locale generated yet: locale_temp_switch($notify_locale); $cache_by_locale[$notify_locale]['subject'] = T_('Activate your account: $login$'); locale_restore_previous(); } $email_template_params = array('locale' => $notify_locale, 'status' => $User->get('status'), 'reminder_key' => $reminder_key, 'is_reminder' => $is_reminder); if (!empty($already_received_messages[$User->ID])) { // add already received message list to email body $email_template_params['already_received_messages'] = $already_received_messages[$User->ID]; } // Update notification sender's info from General settings $User->update_sender(true); if (send_mail_to_User($User->ID, $cache_by_locale[$notify_locale]['subject'], 'account_activate', $email_template_params, true)) { // save corresponding user settings right after the email was sent, to prevent not saving if an eroor occurs $email_sent++; // Set last remind activation email date and increase sent reminder emails number in UserSettings $UserSettings->set('last_activation_email', date2mysql($servertimenow), $User->ID); if ($is_reminder) { $reminder_sent_to_user = $UserSettings->get('activation_reminder_count', $User->ID); $UserSettings->set('activation_reminder_count', $reminder_sent_to_user + 1, $User->ID); } $UserSettings->dbupdate(); } } return $email_sent; }
/** * Send an email to the user with a link to validate/confirm his email address. * * If the email could get sent, it saves the used "request_id" into the user's Session. * * @param string URL, where to redirect the user after he clicked the validation link (gets saved in Session). * @return boolean True, if the email could get sent; false if not */ function send_validate_email($redirect_to_after, $blog = NULL, $email_changed = false) { global $app_name, $Session, $secure_htsrv_url, $baseurl, $servertimenow; global $Settings, $UserSettings; // Display messages depending on user email status display_user_email_status_message($this->ID); if ($Settings->get('validation_process') == 'easy') { // validation process is set to easy, send and easy activation email return send_easy_validate_emails(array($this->ID), false, $email_changed); } if (mail_is_blocked($this->email)) { // prevent trying to send an email to a blocked email address ( Note this is checked in the send_easy_validate_emails too ) return false; } if (empty($redirect_to_after)) { // redirect to was not set $redirect_to_after = param('redirect_to', 'url', ''); if (empty($redirect_to_after)) { if (is_admin_page()) { $redirect_to_after = regenerate_url('action'); } else { $redirect_to_after = $this->get_userpage_url(); } } } $request_id = generate_random_key(22); $blog_param = empty($blog) ? '' : '&inskin=1&blog=' . $blog; // Change locale here to localize the email subject and content locale_temp_switch($this->get('locale')); $email_template_params = array('status' => $this->status, 'blog_param' => $blog_param, 'request_id' => $request_id); $r = send_mail_to_User($this->ID, T_('Activate your account: $login$'), 'account_activate', $email_template_params, true); locale_restore_previous(); if ($r) { // save request_id into Session $request_ids = $Session->get('core.validatemail.request_ids'); if (!is_array($request_ids) || $email_changed) { // create new request ids array if it doesn't exist yet, or if user email changed ( this way the old request into the old email address won't be valid ) $request_ids = array(); } $request_ids[] = $request_id; $Session->set('core.validatemail.request_ids', $request_ids, 86400 * 2); // expires in two days (or when clicked) // set a redirect_to session variable because this way after the account will be activated we will know where to redirect $Session->set('core.validatemail.redirect_to', $redirect_to_after); $Session->dbsave(); // save immediately // update last activation email timestamp $UserSettings->set('last_activation_email', date2mysql($servertimenow), $this->ID); $UserSettings->dbupdate(); } return $r; }
/** * Memorize the blocked emails in cache array in order to display the message * @see blocked_emails_display() * * @param string Email address */ function blocked_emails_memorize($email) { global $current_User, $cache_blocked_emails; if (empty($email)) { // Empty email, Exit here return; } if (is_logged_in() && $current_User->check_perm('users', 'view')) { // User has permissions to view other users if (mail_is_blocked($email)) { // Check if the email address is blocked if (isset($cache_blocked_emails[$email])) { // Icrease a count of blocked email $cache_blocked_emails[$email]++; } else { $cache_blocked_emails[$email] = 1; } } } }