'Mailgun', 'description' => 'Configure Mailgun settings.', 'page callback' => 'drupal_get_form', 'page arguments' => array('mailgun_admin_settings'), 'access arguments' => array('administer mailgun'), 'file' => 'mailgun.admin.inc', ); $items['admin/config/system/mailgun/settings'] = array( 'title' => 'Settings', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => 0, ); $items['admin/config/system/mailgun/test'] = array( 'title' => 'Send test email', 'page callback' => 'drupal_get_form', 'page arguments' => array('mailgun_test_form'), 'access arguments' => array('administer mailgun'), 'description' => 'Send a test e-mail using the Mailgun API.', 'file' => 'mailgun.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); return $items; } /** * Implements hook_permission(). */ function mailgun_permission() { return array( 'administer mailgun' => array( 'title' => t('Administer Mailgun'), 'description' => t('Perform administration tasks for the Mailgun e-mail sending service.'), "restrict access" => TRUE, ), ); } /** * Implements hook_help(). */ function mailgun_help($path, $arg) { switch ($path) { case 'admin/config/system/mailgun': return '

' . t('See documentation for instructions on installing and configuring Mailgun.', array('@url' => url('https://www.drupal.org/node/2547591'))) . '

'; break; case 'admin/config/system/mailgun/test': return '

' . t('Use this form to send a test e-mail to ensure you have correctly configured Mailgun.') . '

'; break; } } /** * Implements hook_cron_queue_info(). */ function mailgun_cron_queue_info() { $queues = array(); $queues['mailgun_queue'] = array( 'worker callback' => 'mailgun_send', 'time' => 60, ); return $queues; } /** * Implements hook_mail(). */ function mailgun_mail($key, &$message, $params) { switch ($key) { case 'test': $message['subject'] = t('Mailgun test email'); $message['body'] = $params['message']; if ($params['attachment']) { $message['params']['attachments'] = array(drupal_realpath('misc/druplicon.png')); } break; } } /** * Implements hook_libraries_info(). */ function mailgun_libraries_info() { $libraries['mailgun'] = array( 'name' => 'Mailgun PHP library', 'vendor url' => 'https://documentation.mailgun.com/wrappers.html#php', 'download url' => 'https://github.com/mailgun/mailgun-php/archive/v1.7.2.zip', 'path' => 'vendor', 'version arguments' => array( 'file' => 'src/Mailgun/Constants/Constants.php', // const SDK_VERSION = "1.7"; 'pattern' => '/const SDK_VERSION = \"((\d+)\.(\d+))\";/', ), 'files' => array( 'php' => array('autoload.php'), ), ); return $libraries; } /** * Get the Mailgun client to access Mailgun's endpoints. * * @param string $key * The Mailgun API key. Leave empty to use the API key saved in database. */ function mailgun_get_client($key = '') { // Check if the Mailgun PHP library is installed. $library = libraries_load('mailgun'); if (!$library['installed']) { watchdog('mailgun', 'Mailgun client initialization failed: Unable to load the Mailgun PHP library.', NULL, WATCHDOG_ERROR); return FALSE; } $key = (empty($key)) ? variable_get('mailgun_api_key', '') : $key; if (empty($key)) { watchdog('mailgun', 'Mailgun client initialization failed: Missing API key.', NULL, WATCHDOG_ERROR); return FALSE; } $client = new \Mailgun\Mailgun($key); return $client; } /** * Send an e-mail using the Mailgun API. * * @param array $mailgun_message * A Mailgun message array. Contains the following keys: * - from: The e-mail addressthe message will be sent from. * - to: The e-mail addressthe message will be sent to. * - subject: The subject of the message. * - text: The plain-text version of the message. Processed using check_plain(). * - html: The original message content. May contain HTML tags. * - cc: One or more carbon copy recipients. If multiple, separate with commas. * - bcc: One or more blind carbon copy recipients. If multiple, separate with commas. * - o:tag: An array containing the tags to add to the message. See: https://documentation.mailgun.com/user_manual.html#tagging. * - o:campaign: The campaign ID this message belongs to. See: https://documentation.mailgun.com/user_manual.html#um-campaign-analytics. * - o:deliverytime: Desired time of delivery. Messages can be scheduled for a maximum of 3 days in the future. See: https://documentation.mailgun.com/api-intro.html#date-format. * - o:dkim: Boolean indicating whether or not to enable DKIM signatures on per-message basis. * - o:testmode: Boolean indicating whether or not to enable test mode. See: https://documentation.mailgun.com/user_manual.html#manual-testmode. * - o:tracking: Boolean indicating whether or not to toggle tracking on a per-message basis. See: https://documentation.mailgun.com/user_manual.html#tracking-messages. * - o:tracking-clicks: Boolean or string "htmlonly" indicating whether or not to toggle clicks tracking on a per-message basis. Has higher priority than domain-level setting. * - o:tracking-opens: Boolean indicating whether or not to toggle clicks tracking on a per-message basis. Has higher priority than domain-level setting. * - h:X-My-Header: h: prefix followed by an arbitrary value allows to append a custom MIME header to the message (X-My-Header in this case). For example, h:Reply-To to specify Reply-To address. * - v:my-var: v: prefix followed by an arbitrary name allows to attach a custom JSON data to the message. See: https://documentation.mailgun.com/user_manual.html#manual-customdata. * * @return bool * TRUE if the mail was successfully accepted, FALSE otherwise. */ function mailgun_send($mailgun_message) { $client = mailgun_get_client(); if (!$client) { return FALSE; } // Test mode if (variable_get('mailgun_test', FALSE)) { $mailgun_message['o:testmode'] = 'yes'; } // Merge the $mailgun_message array with options. $mailgun_message += $mailgun_message['params']; unset($mailgun_message['params']); if (variable_get('mailgun_domain', '_sender') == '_sender') { // Extract the domain from the sender's email address. Use regular expression to check since it could be either a plain email address or in the form "Name ". $tokens = (preg_match('/^\s*(.+?)\s*<\s*([^>]+)\s*>$/', $mailgun_message['from'], $matches) === 1) ? explode('@', $matches[2]) : explode('@', $mailgun_message['from']); $mail_domain = array_pop($tokens); // Retrieve a list of available domains first. $domains = array(); try { $result = $client->get('domains'); if ($result->http_response_code == 200) { foreach ($result->http_response_body->items as $item) { $domains[$item->name] = $item->name; } } else { watchdog('mailgun', 'Mailgun server returned a %code error. Could not retrieve domain list.', array('%code' => $result->http_response_code), WATCHDOG_ERROR); } } catch (Exception $e) { watchdog('mailgun', 'An exception occurred while retrieving domains. @code: @message', array('@code' => $e->getCode(), '@message' => $e->getMessage()), WATCHDOG_ERROR); } if (empty($domains)) { // No domain available. Although this shouldn't happen, doesn't hurt to check. return FALSE; } // Now, we need to get the working domain. This is generally the domain the From address is on or the root domain of it. $working_domain = ''; if ($key = array_search($mail_domain, $domains) !== FALSE) { // Great. Found it. $working_domain = $mail_domain; } else { // Oops. No match. Perhaps it's a subdomain instead. foreach ($domains as $domain) { if (strpos($domain, $mail_domain) !== FALSE) { // Got it. $working_domain = $domain; break; } } } // There is a chance that the user is attempting to send from an email address that's on a domain not yet added to the Mailgun account. // In that case, abort sending and report error. if (empty($working_domain)) { watchdog('mailgun', 'Unable to locate a working domain for From address %mail. Aborting sending.', array('%mail' => $mailgun_message['from']), WATCHDOG_ERROR); return FALSE; } } else { $working_domain = variable_get('mailgun_domain', ''); } // Attachments $post_data = array(); if (!empty($mailgun_message['attachments'])) { // Send message with attachments. $post_data['attachment'] = $mailgun_message['attachments']; unset($mailgun_message['attachments']); } try { $result = $client->sendMessage($working_domain, $mailgun_message, $post_data); // For a list of HTTP response codes, see: https://documentation.mailgun.com/api-intro.html#errors. if ($result->http_response_code == 200) { if (variable_get('mailgun_log', FALSE)) { watchdog('mailgun', 'Successfully sent message from %from to %to. %code: %message.', array('%from' => $mailgun_message['from'], '%to' => $mailgun_message['to'], '%code' => $result->http_response_code, '%message' => $result->http_response_body->message)); } return TRUE; } else { watchdog('mailgun', 'Failed to send message from %from to %to. %code: %message.', array('%from' => $mailgun_message['from'], '%to' => $mailgun_message['to'], '%code' => $result->http_response_code, '%message' => $result->http_response_body->message), WATCHDOG_ERROR); return FALSE; } } catch (Exception $e) { watchdog('mailgun', 'Exception occurred while trying to send test email from %from to %to. @code: @message.', array('%from' => $mailgun_message['from'], '%to' => $mailgun_message['to'], '@code' => $e->getCode(), '@message' => $e->getMessage())); } }