/** * Implements MailSystemInterface::format(). */ public function format(array $message) { // Join the body array into one string. $message['body'] = implode("\n\n", $message['body']); // Wrap the mail body for sending. $message['body'] = MailFormatHelper::wrapMail($message['body']); return $message; }
/** * {@inheritdoc} */ public function format(array $message) { // Join the body array into one string. $message['body'] = implode("\n\n", $message['body']); // Convert any HTML to plain-text. $message['body'] = MailFormatHelper::htmlToText($message['body']); // Wrap the mail body for sending. $message['body'] = MailFormatHelper::wrapMail($message['body']); return $message; }
/** * Concatenate and wrap the e-mail body for either * plain-text or HTML emails. * * @param $message * A message array, as described in hook_mail_alter(). * * @return * The formatted $message. */ public function format(array $message) { $this->AllowHtml = $this->smtpConfig->get('smtp_allowhtml'); // Join the body array into one string. $message['body'] = implode("\n\n", $message['body']); if ($this->AllowHtml == 0) { // Convert any HTML to plain-text. $message['body'] = MailFormatHelper::htmlToText($message['body']); // Wrap the mail body for sending. $message['body'] = MailFormatHelper::wrapMail($message['body']); } return $message; }
/** * HTML to text conversion for HTML and special characters. * * Converts some special HTML characters in addition to * \Drupal\Core\Mail\MailFormatHelper\MailFormatHelper::htmlToText(). * * @param string $text * The mail text with HTML and special characters. * @param bool $inline_hyperlinks * TRUE: URLs will be placed inline. * FALSE: URLs will be converted to numbered reference list. * * @return string * The target text with HTML and special characters replaced. */ public static function htmlToText($text, $inline_hyperlinks = TRUE) { // By replacing <a> tag by only its URL the URLs will be placed inline // in the email body and are not converted to a numbered reference list // by MailFormatHelper::htmlToText(). // URL are converted to absolute URL as drupal_html_to_text() would have. if ($inline_hyperlinks) { $pattern = '@<a[^>]+?href="([^"]*)"[^>]*?>(.+?)</a>@is'; $text = preg_replace_callback($pattern, '\\Drupal\\simplenews\\Mail\\MailFormatHelper::absoluteMailUrls', $text); } // Replace some special characters before performing the drupal standard conversion. $preg = static::getReplacePatterns(); $text = preg_replace(array_keys($preg), array_values($preg), $text); // Perform standard drupal html to text conversion. return \Drupal\Core\Mail\MailFormatHelper::htmlToText($text); }
/** * Makes sure that drupal_wrap_mail() wraps the correct types of lines. */ public function testWrapMail() { $delimiter = "End of header\n"; $long_file_name = $this->randomMachineName(64) . '.docx'; $headers_in_body = 'Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document; name="' . $long_file_name . "\"\n"; $headers_in_body .= "Content-Transfer-Encoding: base64\n"; $headers_in_body .= 'Content-Disposition: attachment; filename="' . $long_file_name . "\"\n"; $headers_in_body .= 'Content-Description: ' . $this->randomMachineName(64); $body = $this->randomMachineName(76) . ' ' . $this->randomMachineName(6); $wrapped_text = MailFormatHelper::wrapMail($headers_in_body . $delimiter . $body); list($processed_headers, $processed_body) = explode($delimiter, $wrapped_text); // Check that the body headers were not wrapped even though some exceeded // 77 characters. $this->assertEquals($headers_in_body, $processed_headers, 'Headers in the body are not wrapped.'); // Check that the body text is wrapped. $this->assertEquals(wordwrap($body, 77, " \n"), $processed_body, 'Body text is wrapped.'); }
/** * {@inheritdoc} */ public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) { $build = parent::view($entity, $view_mode, $langcode); if ($view_mode == 'mail') { // Convert field labels into headings. // @todo Improve \Drupal\Core\Mail\MailFormatHelper::htmlToText() to // convert DIVs correctly. foreach (Element::children($build) as $key) { if (isset($build[$key]['#label_display']) && $build[$key]['#label_display'] == 'above') { $build[$key] += array('#prefix' => ''); $build[$key]['#prefix'] = $build[$key]['#title'] . ":\n"; $build[$key]['#label_display'] = 'hidden'; } } $build = array('#markup' => MailFormatHelper::htmlToText(drupal_render($build))); } return $build; }
/** * Tests auto-reply on the site-wide contact form. */ function testAutoReply() { // Create and login administrative user. $admin_user = $this->drupalCreateUser(array('access site-wide contact form', 'administer contact forms', 'administer permissions', 'administer users')); $this->drupalLogin($admin_user); // Set up three forms, 2 with an auto-reply and one without. $foo_autoreply = $this->randomMachineName(40); $bar_autoreply = $this->randomMachineName(40); $this->addContactForm('foo', 'foo', '*****@*****.**', $foo_autoreply, FALSE); $this->addContactForm('bar', 'bar', '*****@*****.**', $bar_autoreply, FALSE); $this->addContactForm('no_autoreply', 'no_autoreply', '*****@*****.**', '', FALSE); // Log the current user out in order to test the name and email fields. $this->drupalLogout(); user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, array('access site-wide contact form')); // Test the auto-reply for form 'foo'. $email = $this->randomMachineName(32) . '@example.com'; $subject = $this->randomMachineName(64); $this->submitContact($this->randomMachineName(16), $email, $subject, 'foo', $this->randomString(128)); // We are testing the auto-reply, so there should be one email going to the sender. $captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email)); $this->assertEqual(count($captured_emails), 1); $this->assertEqual(trim($captured_emails[0]['body']), trim(MailFormatHelper::htmlToText($foo_autoreply))); // Test the auto-reply for form 'bar'. $email = $this->randomMachineName(32) . '@example.com'; $this->submitContact($this->randomMachineName(16), $email, $this->randomString(64), 'bar', $this->randomString(128)); // Auto-reply for form 'bar' should result in one auto-reply email to the sender. $captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email)); $this->assertEqual(count($captured_emails), 1); $this->assertEqual(trim($captured_emails[0]['body']), trim(MailFormatHelper::htmlToText($bar_autoreply))); // Verify that no auto-reply is sent when the auto-reply field is left blank. $email = $this->randomMachineName(32) . '@example.com'; $this->submitContact($this->randomMachineName(16), $email, $this->randomString(64), 'no_autoreply', $this->randomString(128)); $captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email)); $this->assertEqual(count($captured_emails), 0); }
/** * Tests that trailing whitespace from Usenet style signatures is not removed. * * RFC 3676 says, "This is a special case; an (optionally quoted or quoted and * stuffed) line consisting of DASH DASH SP is neither fixed nor flowed." * * @see \Drupal\Core\Mail\MailFormatHelper::wrapMail() */ public function testUsenetSignature() { $text = "Hi there!\n-- \nHerp Derp"; $mail_lines = explode("\n", MailFormatHelper::wrapMail($text)); $this->assertEqual("-- ", $mail_lines[1], 'Trailing whitespace not removed for dash-dash-space signatures.'); $text = "Hi there!\n-- \nHerp Derp"; $mail_lines = explode("\n", MailFormatHelper::wrapMail($text)); $this->assertEqual("--", $mail_lines[1], 'Trailing whitespace removed for incorrect dash-dash-space signatures.'); }
/** * Generate a multipart message body with a text alternative for some HTML text. * * @param string $body * The HTML message body. * @param string $subject * The message subject. * @param boolean $plain * (optional) Whether the recipient prefers plaintext-only messages. Defaults to FALSE. * @param string $plaintext * (optional) The plaintext message body. * @param array $attachments * (optional) The files to be attached to the message. * * @return array * An associative array containing the following elements: * - body: A string containing the MIME-encoded multipart body of a mail. * - headers: An array that includes some headers for the mail to be sent. * * The first mime part is a multipart/alternative containing mime-encoded sub-parts for * HTML and plaintext. Each subsequent part is the required image or attachment. */ public static function mimeMailHtmlBody($body, $subject, $plain = FALSE, $plaintext = NULL, $attachments = array()) { if (empty($plaintext)) { // @todo Remove once filter_xss() can handle direct descendant selectors in inline CSS. // @see http://drupal.org/node/1116930 // @see http://drupal.org/node/370903 // Pull out the message body. preg_match('|<body.*?</body>|mis', $body, $matches); $plaintext = MailFormatHelper::htmlToText($matches[0]); } if ($plain) { // Plain mail without attachment. if (empty($attachments)) { $content_type = 'text/plain'; return array('body' => $plaintext, 'headers' => array('Content-Type' => 'text/plain; charset=utf-8')); } else { $content_type = 'multipart/mixed'; $parts = array(array('content' => $plaintext, 'Content-Type' => 'text/plain; charset=utf-8')); } } else { $content_type = 'multipart/mixed'; $plaintext_part = array('Content-Type' => 'text/plain; charset=utf-8', 'content' => $plaintext); // Expand all local links. $pattern = '/(<a[^>]+href=")([^"]*)/mi'; $body = preg_replace_callback($pattern, ['\\Drupal\\mimemail\\Utility\\MimeMailFormatHelper', 'expandLinks'], $body); $mime_parts = static::mimeMailExtractFiles($body); $content = array($plaintext_part, array_shift($mime_parts)); $content = static::mimeMailMultipartBody($content, 'multipart/alternative', TRUE); $parts = array(array('Content-Type' => $content['headers']['Content-Type'], 'content' => $content['body'])); if ($mime_parts) { $parts = array_merge($parts, $mime_parts); $content = static::mimeMailMultipartBody($parts, 'multipart/related; type="multipart/alternative"', TRUE); $parts = array(array('Content-Type' => $content['headers']['Content-Type'], 'content' => $content['body'])); } } if (is_array($attachments) && !empty($attachments)) { foreach ($attachments as $a) { $a = (object) $a; $path = isset($a->uri) ? $a->uri : (isset($a->filepath) ? $a->filepath : NULL); $content = isset($a->filecontent) ? $a->filecontent : NULL; $name = isset($a->filename) ? $a->filename : NULL; $type = isset($a->filemime) ? $a->filemime : NULL; static::mimeMailFile($path, $content, $name, $type, 'attachment'); $parts = array_merge($parts, static::mimeMailFile()); } } return static::mimeMailMultipartBody($parts, $content_type); }
/** * Prepares the message for sending. * * @param array $message * An array containing the message data. The optional parameters are: * - plain: Whether to send the message as plaintext only or HTML. If evaluates to TRUE, * then the message will be sent as plaintext. * - plaintext: Optional plaintext portion of a multipart email. * - attachments: An array of arrays which describe one or more attachments. * Existing files can be added by path, dinamically-generated files * can be added by content. The internal array contains the following elements: * - filepath: Relative Drupal path to an existing file (filecontent is NULL). * - filecontent: The actual content of the file (filepath is NULL). * - filename: The filename of the file. * - filemime: The MIME type of the file. * The array of arrays looks something like this: * Array * ( * [0] => Array * ( * [filepath] => '/sites/default/files/attachment.txt' * [filecontent] => 'My attachment.' * [filename] => 'attachment.txt' * [filemime] => 'text/plain' * ) * ) * * @return array * All details of the message. */ public function prepareMessage(array $message) { $module = $message['module']; $key = $message['key']; $to = $message['to']; $from = $message['from']; $subject = $message['subject']; $body = $message['body']; $headers = isset($message['params']['headers']) ? $message['params']['headers'] : array(); $plain = isset($message['params']['plain']) ? $message['params']['plain'] : NULL; $plaintext = isset($message['params']['plaintext']) ? $message['params']['plaintext'] : NULL; $attachments = isset($message['params']['attachments']) ? $message['params']['attachments'] : array(); $site_name = \Drupal::config('system.site')->get('name'); //$site_mail = variable_get('site_mail', ini_get('sendmail_from')); $site_mail = \Drupal::config('system.site')->get('mail'); /*$simple_address = variable_get('mimemail_simple_address', 0);*/ // Override site mails default sender when using default engine. /*if ((empty($from) || $from == $site_mail) && variable_get('mimemail_engine', 'mimemail') == 'mimemail') { $mimemail_name = variable_get('mimemail_name', $site_name); $mimemail_mail = variable_get('mimemail_mail', $site_mail); $from = array( 'name' => !empty($mimemail_name) ? $mimemail_name : $site_name, 'mail' => !empty($mimemail_mail) ? $mimemail_mail : $site_mail, ); }*/ // Override site mails default sender when using default engine. if (empty($from) || $from == $site_mail) { $mimemail_name = \Drupal::config('mimemail.settings')->get('name'); $mimemail_mail = \Drupal::config('mimemail.settings')->get('mail'); $from = array('name' => !empty($mimemail_name) ? $mimemail_name : $site_name, 'mail' => !empty($mimemail_mail) ? $mimemail_mail : $site_mail); } // Body is empty, this is a plaintext message. if (empty($body)) { $plain = TRUE; } elseif (is_null($plain)) { if (is_object($to) && isset($to->data['mimemail_textonly'])) { $plain = $to->data['mimemail_textonly']; } elseif (is_string($to) && \Drupal::service('email.validator')->isValid($to)) { if (is_object($account = user_load_by_mail($to)) && isset($account->data['mimemail_textonly'])) { $plain = $account->data['mimemail_textonly']; // Might as well pass the user object to the address function. $to = $account; } } } // Removing newline character introduced by _drupal_wrap_mail_line(); $subject = str_replace(array("\n"), '', trim(MailFormatHelper::htmlToText($subject))); $hook = array('mimemail_message__' . $key, 'mimemail_message__' . $module . '__' . $key); $body = ['#theme' => 'mimemail_messages', '#module' => $module, '#key' => $key, '#recipient' => $to, '#subject' => $subject, '#body' => $body]; $body = \Drupal::service('renderer')->render($body); /*foreach (module_implements('mail_post_process') as $module) { $function = $module . '_mail_post_process'; $function($body, $key); }*/ //$plain = $plain || variable_get('mimemail_textonly', 0); $from = MimeMailFormatHelper::mimeMailAddress($from); $mail = MimeMailFormatHelper::mimeMailHtmlBody($body, $subject, $plain, $plaintext, $attachments); $headers = array_merge($message['headers'], $headers, $mail['headers']); //$message['to'] = MimeMailFormatHelper::mimeMailAddress($to, $simple_address); $message['to'] = MimeMailFormatHelper::mimeMailAddress($to); $message['from'] = $from; $message['subject'] = $subject; $message['body'] = $mail['body']; $message['headers'] = MimeMailFormatHelper::mimeMailHeaders($headers, $from); return $message; }
/** * Applies a markdown function to a string. * * @param $markdown * Key of the markdown function to be applied to the items. * One of drupal_html_to_text, filter_xss, filter_xss_all. * @param $items * String to be processed. * * @return array|string * Result after markdown was applied on $items. */ protected function applyMarkdown($markdown, $items) { if (!$markdown) { return $items; } if ($markdown == 'drupal_html_to_text') { return trim(MailFormatHelper::htmlToText($items), "\n"); } elseif ($markdown == 'filter_xss') { return trim(Xss::filter($items), "\n"); } elseif ($markdown == 'filter_xss_all') { return trim(Xss::filter($items, array()), "\n"); } else { return $items; } }
/** * Tests auto-reply on the site-wide contact form. */ function testAutoReply() { // Create and log in administrative user. $admin_user = $this->drupalCreateUser(['access site-wide contact form', 'administer contact forms', 'administer permissions', 'administer users', 'access site reports']); $this->drupalLogin($admin_user); // Set up three forms, 2 with an auto-reply and one without. $foo_autoreply = $this->randomMachineName(40); $bar_autoreply = $this->randomMachineName(40); $this->addContactForm('foo', 'foo', '*****@*****.**', $foo_autoreply, FALSE); $this->addContactForm('bar', 'bar', '*****@*****.**', $bar_autoreply, FALSE); $this->addContactForm('no_autoreply', 'no_autoreply', '*****@*****.**', '', FALSE); // Log the current user out in order to test the name and email fields. $this->drupalLogout(); user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, array('access site-wide contact form')); // Test the auto-reply for form 'foo'. $email = $this->randomMachineName(32) . '@example.com'; $subject = $this->randomMachineName(64); $this->submitContact($this->randomMachineName(16), $email, $subject, 'foo', $this->randomString(128)); // We are testing the auto-reply, so there should be one email going to the sender. $captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email)); $this->assertEqual(count($captured_emails), 1); $this->assertEqual(trim($captured_emails[0]['body']), trim(MailFormatHelper::htmlToText($foo_autoreply))); // Test the auto-reply for form 'bar'. $email = $this->randomMachineName(32) . '@example.com'; $this->submitContact($this->randomMachineName(16), $email, $this->randomString(64), 'bar', $this->randomString(128)); // Auto-reply for form 'bar' should result in one auto-reply email to the sender. $captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email)); $this->assertEqual(count($captured_emails), 1); $this->assertEqual(trim($captured_emails[0]['body']), trim(MailFormatHelper::htmlToText($bar_autoreply))); // Verify that no auto-reply is sent when the auto-reply field is left blank. $email = $this->randomMachineName(32) . '@example.com'; $this->submitContact($this->randomMachineName(16), $email, $this->randomString(64), 'no_autoreply', $this->randomString(128)); $captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email)); $this->assertEqual(count($captured_emails), 0); // Verify that the current error message doesn't show, that the auto-reply // doesn't get sent and the correct silent error gets logged. $email = ''; entity_get_form_display('contact_message', 'foo', 'default')->removeComponent('mail')->save(); $this->submitContact($this->randomMachineName(16), $email, $this->randomString(64), 'foo', $this->randomString(128)); $this->assertNoText('Unable to send email. Contact the site administrator if the problem persists.'); $captured_emails = $this->drupalGetMails(['id' => 'contact_page_autoreply', 'to' => $email]); $this->assertEqual(count($captured_emails), 0); $this->drupalLogin($admin_user); $this->drupalGet('admin/reports/dblog'); $this->assertRaw('Error sending auto-reply, missing sender e-mail address in foo'); }
/** * {@inheritdoc} */ public function buildRow(EntityInterface $entity) { $row['label'] = $entity->label(); $row['source'] = $entity->isUserGenerated() ? t('User') : t('System'); $row['description'] = MailFormatHelper::htmlToText($entity->getDescription()); return $row + parent::buildRow($entity); }