mimemail.module 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <?php
  2. /**
  3. * @file
  4. * Component module for sending Mime-encoded emails.
  5. */
  6. /**
  7. * Implements hook_menu().
  8. */
  9. function mimemail_menu() {
  10. $path = drupal_get_path('module', 'mimemail') . '/includes';
  11. // Configuration links.
  12. $items['admin/config/system/mimemail'] = array(
  13. 'title' => 'Mime Mail',
  14. 'description' => 'Manage mime mail system settings.',
  15. 'page callback' => 'drupal_get_form',
  16. 'page arguments' => array('mimemail_admin_settings'),
  17. 'access arguments' => array('administer site configuration'),
  18. 'file' => 'mimemail.admin.inc',
  19. 'file path' => $path,
  20. );
  21. $items['mimemail'] = array(
  22. 'page callback' => 'mimemail_post',
  23. 'access callback' => 'mimemail_incoming_access',
  24. 'type' => MENU_CALLBACK,
  25. 'file' => 'mimemail.incoming.inc',
  26. 'file path' => $path,
  27. );
  28. return $items;
  29. }
  30. /**
  31. * Implements hook_permission().
  32. */
  33. function mimemail_permission() {
  34. return array(
  35. 'edit mimemail user settings' => array(
  36. 'title' => t('Edit Mime Mail user settings'),
  37. 'description' => t('Edit user specific settings for Mime Mail.'),
  38. ),
  39. 'send arbitrary files' => array(
  40. 'title' => t('Send arbitrary files'),
  41. 'description' => t('Attach or embed files located outside the public files directory.'),
  42. 'restrict access' => TRUE,
  43. ),
  44. );
  45. }
  46. /**
  47. * Access callback to process incoming messages.
  48. */
  49. function mimemail_incoming_access() {
  50. return variable_get('mimemail_incoming', FALSE);
  51. }
  52. /**
  53. * Implements hook_field_extra_fields().
  54. */
  55. function mimemail_field_extra_fields() {
  56. $extra['user']['user'] = array(
  57. 'form' => array(
  58. 'mimemail' => array(
  59. 'label' => t('Email'),
  60. 'description' => t('Mime Mail module settings form elements.'),
  61. 'weight' => 0,
  62. ),
  63. ),
  64. 'display' => array(
  65. 'mimemail' => array(
  66. 'label' => t('Email'),
  67. 'description' => t('Mime Mail module settings form elements.'),
  68. 'weight' => 0,
  69. ),
  70. ),
  71. );
  72. return $extra;
  73. }
  74. /**
  75. * Implements hook_user_view().
  76. */
  77. function mimemail_user_view($account, $view_mode, $langcode) {
  78. $account->content['mimemail'] = array(
  79. '#type' => 'user_profile_category',
  80. '#title' => t('Email'),
  81. );
  82. $account->content['mimemail']['textonly'] = array(
  83. '#type' => 'user_profile_item',
  84. '#title' => t('Plaintext email only'),
  85. '#markup' => empty($account->data['mimemail_textonly']) ? t('No') : t('Yes'),
  86. );
  87. }
  88. /**
  89. * Implements hook_form_FORM_ID_alter().
  90. *
  91. * Adds the Mime Mail settings on the user settings page.
  92. */
  93. function mimemail_form_user_profile_form_alter(&$form, &$form_state) {
  94. if ($form['#user_category'] == 'account') {
  95. $account = $form['#user'];
  96. $form['mimemail'] = array(
  97. '#type' => 'fieldset',
  98. '#title' => t('Email settings'),
  99. '#weight' => 5,
  100. '#collapsible' => TRUE,
  101. '#access' => user_access('edit mimemail user settings'),
  102. );
  103. $form['mimemail']['mimemail_textonly'] = array(
  104. '#type' => 'checkbox',
  105. '#title' => t('Plaintext email only'),
  106. '#default_value' => !empty($account->data['mimemail_textonly']) ? $account->data['mimemail_textonly'] : FALSE,
  107. '#description' => t('Check this option if you do not wish to receive email messages with graphics and styles.'),
  108. );
  109. }
  110. }
  111. /**
  112. * Implements hook_user_presave().
  113. */
  114. function mimemail_user_presave(&$edit, $account, $category) {
  115. $edit['data']['mimemail_textonly'] = isset($edit['mimemail_textonly']) ? $edit['mimemail_textonly'] : 0;
  116. }
  117. /**
  118. * Implements hook_theme().
  119. */
  120. function mimemail_theme() {
  121. module_load_include('inc', 'mimemail', 'theme/mimemail.theme');
  122. return mimemail_theme_theme();
  123. }
  124. /**
  125. * Implements hook_mail().
  126. */
  127. function mimemail_mail($key, &$message, $params) {
  128. $context = $params['context'];
  129. $options = array('clear' => TRUE);
  130. // Prepare the array of the attachments.
  131. $attachments = array();
  132. $attachments_string = trim($params['attachments']);
  133. if (!empty($attachments_string)) {
  134. $attachment_lines = array_filter(explode("\n", trim($attachments_string)));
  135. foreach ($attachment_lines as $filepath) {
  136. $attachments[] = array(
  137. 'filepath' => trim($filepath),
  138. );
  139. }
  140. }
  141. // We handle different address headers if set.
  142. $address_headers = array(
  143. 'cc' => 'Cc',
  144. 'bcc' => 'Bcc',
  145. 'reply-to' => 'Reply-to',
  146. 'list-unsubscribe' => 'List-Unsubscribe',
  147. );
  148. foreach ($address_headers as $param_key => $address_header) {
  149. $params[$param_key] = empty($params[$param_key]) ? array() : explode(',', $params[$param_key]);
  150. if (!empty($params[$param_key])) {
  151. foreach ($params[$param_key] as $key => $address) {
  152. $params[$param_key][$key] = token_replace($address, $context, $options);
  153. }
  154. $message['headers'][$address_header] = implode(',', $params[$param_key]);
  155. }
  156. }
  157. $message['to'] = token_replace($message['to'], $context, $options);
  158. $message['subject'] = token_replace($context['subject'], $context, $options);
  159. $message['body'][] = token_replace($context['body'], $context, $options);
  160. $message['params']['plaintext'] = token_replace($params['plaintext'], $context, $options);
  161. $message['params']['attachments'] = $attachments;
  162. }
  163. /**
  164. * Retreives a list of all available mailer engines.
  165. *
  166. * @return array
  167. * Mailer engine names.
  168. */
  169. function mimemail_get_engines() {
  170. $engines = array();
  171. foreach (module_implements('mailengine') as $module) {
  172. $engines[$module] = module_invoke($module, 'mailengine', 'list');
  173. }
  174. return $engines;
  175. }
  176. /**
  177. * Implements hook_mailengine().
  178. *
  179. * @param string $op
  180. * The operation to perform on the message.
  181. * @param array $message
  182. * The message to perform the operation on.
  183. *
  184. * @return boolean
  185. * Returns TRUE if the operation was successful or FALSE if it was not.
  186. */
  187. function mimemail_mailengine($op, $message = array()) {
  188. module_load_include('inc', 'mimemail');
  189. switch ($op) {
  190. case 'list':
  191. $engine = array(
  192. 'name' => t('Mime Mail'),
  193. 'description' => t("Default mailing engine."),
  194. );
  195. return $engine;
  196. case 'settings':
  197. // Not implemented.
  198. break;
  199. case 'multiple':
  200. case 'single':
  201. case 'send':
  202. // Default values.
  203. $default = array(
  204. 'to' => '',
  205. 'subject' => '',
  206. 'body' => '',
  207. 'from' => '',
  208. 'headers' => ''
  209. );
  210. $message = array_merge($default, $message);
  211. // If 'Return-Path' isn't already set in php.ini, we pass it separately
  212. // as an additional parameter instead of in the header.
  213. // However, if PHP's 'safe_mode' is on, this is not allowed.
  214. if (isset($message['headers']['Return-Path']) && !ini_get('safe_mode')) {
  215. $return_path_set = strpos(ini_get('sendmail_path'), ' -f');
  216. if (!$return_path_set) {
  217. $return_path = trim($message['headers']['Return-Path'], '<>');
  218. unset($message['headers']['Return-Path']);
  219. }
  220. }
  221. $crlf = variable_get('mimemail_crlf', MAIL_LINE_ENDINGS);
  222. $recipients = (!is_array($message['to'])) ? array($message['to']) : $message['to'];
  223. $subject = mime_header_encode($message['subject']);
  224. $body = preg_replace('@\r?\n@', $crlf, $message['body']);
  225. $headers = mimemail_rfc_headers($message['headers']);
  226. $result = TRUE;
  227. foreach ($recipients as $to) {
  228. if (isset($return_path) && !empty($return_path)) {
  229. if (isset($_SERVER['WINDIR']) || strpos($_SERVER['SERVER_SOFTWARE'], 'Win32') !== FALSE) {
  230. // On Windows, PHP will use the value of sendmail_from for the
  231. // Return-Path header.
  232. $old_from = ini_get('sendmail_from');
  233. ini_set('sendmail_from', $return_path);
  234. $result = @mail($to, $subject, $body, $headers) && $result;
  235. ini_set('sendmail_from', $old_from);
  236. }
  237. else {
  238. // On most non-Windows systems, the "-f" option to the sendmail command
  239. // is used to set the Return-Path.
  240. $result = @mail($to, $subject, $body, $headers, '-f' . $return_path) && $result;
  241. }
  242. }
  243. else {
  244. // The optional $additional_parameters argument to mail() is not allowed
  245. // if safe_mode is enabled. Passing any value throws a PHP warning and
  246. // makes mail() return FALSE.
  247. $result = @mail($to, $subject, $body, $headers) && $result;
  248. }
  249. }
  250. return $result;
  251. }
  252. return FALSE;
  253. }
  254. /**
  255. * Prepares the message for sending.
  256. *
  257. * @param array $message
  258. * An array containing the message data. The optional parameters are:
  259. * - plain: Whether to send the message as plaintext only or HTML. If evaluates to TRUE,
  260. * then the message will be sent as plaintext.
  261. * - plaintext: Optional plaintext portion of a multipart email.
  262. * - attachments: An array of arrays which describe one or more attachments.
  263. * Existing files can be added by path, dinamically-generated files
  264. * can be added by content. The internal array contains the following elements:
  265. * - filepath: Relative Drupal path to an existing file (filecontent is NULL).
  266. * - filecontent: The actual content of the file (filepath is NULL).
  267. * - filename: The filename of the file.
  268. * - filemime: The MIME type of the file.
  269. * The array of arrays looks something like this:
  270. * Array
  271. * (
  272. * [0] => Array
  273. * (
  274. * [filepath] => '/sites/default/files/attachment.txt'
  275. * [filecontent] => 'My attachment.'
  276. * [filename] => 'attachment.txt'
  277. * [filemime] => 'text/plain'
  278. * )
  279. * )
  280. *
  281. * @return array
  282. * All details of the message.
  283. */
  284. function mimemail_prepare_message($message) {
  285. module_load_include('inc', 'mimemail');
  286. $module = $message['module'];
  287. $key = $message['key'];
  288. $to = $message['to'];
  289. $from = $message['from'];
  290. $subject = $message['subject'];
  291. $body = $message['body'];
  292. $headers = isset($message['params']['headers']) ? $message['params']['headers'] : array();
  293. $plain = isset($message['params']['plain']) ? $message['params']['plain'] : NULL;
  294. $plaintext = isset($message['params']['plaintext']) ? $message['params']['plaintext'] : NULL;
  295. $attachments = isset($message['params']['attachments']) ? $message['params']['attachments'] : array();
  296. $site_name = variable_get('site_name', 'Drupal');
  297. $site_mail = variable_get('site_mail', ini_get('sendmail_from'));
  298. $simple_address = variable_get('mimemail_simple_address', 0);
  299. // Override site mails default sender when using default engine.
  300. if ((empty($from) || $from == $site_mail)
  301. && variable_get('mimemail_engine', 'mimemail') == 'mimemail') {
  302. $mimemail_name = variable_get('mimemail_name', $site_name);
  303. $mimemail_mail = variable_get('mimemail_mail', $site_mail);
  304. $from = array(
  305. 'name' => !empty($mimemail_name) ? $mimemail_name : $site_name,
  306. 'mail' => !empty($mimemail_mail) ? $mimemail_mail : $site_mail,
  307. );
  308. }
  309. // Body is empty, this is a plaintext message.
  310. if (empty($body)) {
  311. $plain = TRUE;
  312. }
  313. // Try to determine recipient's text mail preference.
  314. elseif (is_null($plain)) {
  315. if (is_object($to) && isset($to->data['mimemail_textonly'])) {
  316. $plain = $to->data['mimemail_textonly'];
  317. }
  318. elseif (is_string($to) && valid_email_address($to)) {
  319. if (is_object($account = user_load_by_mail($to)) && isset($account->data['mimemail_textonly'])) {
  320. $plain = $account->data['mimemail_textonly'];
  321. // Might as well pass the user object to the address function.
  322. $to = $account;
  323. }
  324. }
  325. }
  326. // Removing newline character introduced by _drupal_wrap_mail_line();
  327. $subject = str_replace(array("\n"), '', trim(drupal_html_to_text($subject)));
  328. $hook = array(
  329. 'mimemail_message__' . $key,
  330. 'mimemail_message__' . $module .'__'. $key,
  331. );
  332. $variables = array(
  333. 'module' => $module,
  334. 'key' => $key,
  335. 'recipient' => $to,
  336. 'subject' => $subject,
  337. 'body' => $body
  338. );
  339. $body = theme($hook, $variables);
  340. foreach (module_implements('mail_post_process') as $module) {
  341. $function = $module . '_mail_post_process';
  342. $function($body, $key);
  343. }
  344. $plain = $plain || variable_get('mimemail_textonly', 0);
  345. $from = mimemail_address($from);
  346. $mail = mimemail_html_body($body, $subject, $plain, $plaintext, $attachments);
  347. $headers = array_merge($message['headers'], $headers, $mail['headers']);
  348. $message['to'] = mimemail_address($to, $simple_address);
  349. $message['from'] = $from;
  350. $message['subject'] = $subject;
  351. $message['body'] = $mail['body'];
  352. $message['headers'] = mimemail_headers($headers, $from);
  353. return $message;
  354. }