3 namespace Drupal\devel\Plugin\Mail;
5 use Drupal\Component\Utility\Unicode;
6 use Drupal\Core\Config\ConfigFactoryInterface;
7 use Drupal\Core\Mail\MailFormatHelper;
8 use Drupal\Core\Mail\MailInterface;
9 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
10 use Drupal\Core\Site\Settings;
11 use Symfony\Component\DependencyInjection\ContainerInterface;
14 * Defines a mail backend that saves emails as temporary files.
16 * To enable, save a variable in settings.php (or otherwise) whose value
17 * can be as simple as:
19 * $config['system.mail']['interface']['default'] = 'devel_mail_log';
22 * By default the mails are saved in 'temporary://devel-mails'. This setting
23 * can be changed using 'debug_mail_directory' config setting. For example,
25 * $config['devel.settings']['debug_mail_directory'] = 'temporary://my-directory';
28 * The default filename pattern used is '%to-%subject-%datetime.mail.txt'. This
29 * setting can be changed using 'debug_mail_directory' config setting. For example,
31 * $config['devel.settings']['debug_mail_file_format'] = 'devel-mail-%to-%subject-%datetime.mail.txt';
34 * The following placeholders can be used in the filename pattern:
35 * - %to: the email recipient.
36 * - %subject: the email subject.
37 * - %datetime: the current datetime in 'y-m-d_his' format.
40 * id = "devel_mail_log",
41 * label = @Translation("Devel Logging Mailer"),
42 * description = @Translation("Outputs the message as a file in the temporary directory.")
45 class DevelMailLog implements MailInterface, ContainerFactoryPluginInterface {
48 * The devel.settings config object.
50 * @var \Drupal\Core\Config\Config;
55 * Constructs a new DevelMailLog object.
57 * @param array $configuration
58 * A configuration array containing information about the plugin instance.
59 * @param string $plugin_id
60 * The plugin_id for the plugin instance.
61 * @param mixed $plugin_definition
62 * The plugin implementation definition.
63 * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
64 * The config factory service.
66 public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory) {
67 $this->config = $config_factory->get('devel.settings');
73 public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
78 $container->get('config.factory')
85 public function mail(array $message) {
86 $directory = $this->config->get('debug_mail_directory');
88 if (!$this->prepareDirectory($directory)) {
92 $pattern = $this->config->get('debug_mail_file_format');
93 $filename = $this->replacePlaceholders($pattern, $message);
94 $output = $this->composeMessage($message);
96 return (bool) file_put_contents($directory . '/' . $filename, $output);
102 public function format(array $message) {
103 // Join the body array into one string.
104 $message['body'] = implode("\n\n", $message['body']);
106 // Convert any HTML to plain-text.
107 $message['body'] = MailFormatHelper::htmlToText($message['body']);
108 // Wrap the mail body for sending.
109 $message['body'] = MailFormatHelper::wrapMail($message['body']);
115 * Compose the output message.
117 * @param array $message
118 * A message array, as described in hook_mail_alter().
121 * The output message.
123 protected function composeMessage($message) {
125 $message['headers']['To'] = $message['to'];
126 foreach ($message['headers'] as $name => $value) {
127 $mimeheaders[] = $name . ': ' . Unicode::mimeHeaderEncode($value);
130 $line_endings = Settings::get('mail_line_endings', PHP_EOL);
131 $output = join($line_endings, $mimeheaders) . $line_endings;
132 // 'Subject:' is a mail header and should not be translated.
133 $output .= 'Subject: ' . $message['subject'] . $line_endings;
134 // Blank line to separate headers from body.
135 $output .= $line_endings;
136 $output .= preg_replace('@\r?\n@', $line_endings, $message['body']);
141 * Replaces placeholders with sanitized values in a string.
144 * The string that contains the placeholders. The following placeholders
145 * are considered in the replacement:
146 * - %to: replaced by the email recipient value.
147 * - %subject: replaced by the email subject value.
148 * - %datetime: replaced by the current datetime in 'y-m-d_his' format.
149 * @param array $message
150 * A message array, as described in hook_mail_alter().
153 * The formatted string.
155 protected function replacePlaceholders($filename, $message) {
157 '%to' => $message['to'],
158 '%subject' => $message['subject'],
159 '%datetime' => date('y-m-d_his'),
161 $filename = str_replace(array_keys($tokens), array_values($tokens), $filename);
162 return preg_replace('/[^a-zA-Z0-9_\-\.@]/', '_', $filename);
166 * Checks that the directory exists and is writable.
167 * Public directories will be protected by adding an .htaccess which
168 * indicates that the directory is private.
171 * A string reference containing the name of a directory path or URI.
174 * TRUE if the directory exists (or was created), is writable and is
175 * protected (if it is public). FALSE otherwise.
177 protected function prepareDirectory($directory) {
178 if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
181 if (0 === strpos($directory, 'public://')) {
182 return file_save_htaccess($directory);