├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .rubocop.yml ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── bin ├── handler-mailer-mailgun.rb ├── handler-mailer-ses.rb └── handler-mailer.rb ├── certs └── pvt_key ├── lib ├── sensu-plugins-mailer.rb └── sensu-plugins-mailer │ └── version.rb ├── sensu-plugins-mailer.gemspec └── test └── spec_helper.rb /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Pull Request Checklist 2 | 3 | **Is this in reference to an existing issue?** 4 | 5 | #### General 6 | 7 | - [ ] Update Changelog following the conventions laid out [here](https://github.com/sensu-plugins/community/blob/master/HOW_WE_CHANGELOG.md) 8 | 9 | - [ ] Update README with any necessary configuration snippets 10 | 11 | - [ ] Binstubs are created if needed 12 | 13 | - [ ] RuboCop passes 14 | 15 | - [ ] Existing tests pass 16 | 17 | #### New Plugins 18 | 19 | - [ ] Tests 20 | 21 | - [ ] Add the plugin to the README 22 | 23 | - [ ] Does it have a complete header as outlined [here](http://sensu-plugins.io/docs/developer_guidelines.html#coding-style) 24 | 25 | #### Purpose 26 | 27 | #### Known Compatibility Issues 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /Gemfile.lock 4 | /_yardoc/ 5 | /coverage/ 6 | /doc/ 7 | /pkg/ 8 | /spec/reports/ 9 | /tmp/ 10 | *.bundle 11 | *.so 12 | *.o 13 | *.a 14 | mkmf.log 15 | .vagrant/* 16 | .DS_Store 17 | .idea/* 18 | *.gem 19 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | 2 | MethodLength: 3 | Max: 200 4 | 5 | LineLength: 6 | Max: 160 7 | 8 | AbcSize: 9 | Max: 150 10 | 11 | FileName: 12 | Enabled: false 13 | 14 | PerceivedComplexity: 15 | Enabled: false 16 | 17 | CyclomaticComplexity: 18 | Enabled: false 19 | 20 | ClassLength: 21 | Enabled: false 22 | 23 | IfUnlessModifier: 24 | Enabled: false 25 | 26 | RegexpLiteral: 27 | Enabled: false 28 | 29 | Style/Documentation: 30 | Enabled: false 31 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | cache: 3 | - bundler 4 | install: 5 | - bundle install 6 | rvm: 7 | - 2.3.0 8 | - 2.4.1 9 | notifications: 10 | email: 11 | recipients: 12 | - sensu-plugin@sensu-plugins.io 13 | on_success: change 14 | on_failure: always 15 | script: 16 | - bundle exec rake default 17 | - gem build sensu-plugins-mailer.gemspec 18 | - gem install sensu-plugins-mailer-*.gem 19 | deploy: 20 | provider: rubygems 21 | api_key: 22 | secure: pQ5zPr5JYhU/QF4+K4LyBzHBMcYbEBhjwJk6niaN7yMN/GMTdgJqUOKAYcSD6lgl4ok6uLouWxTdVhM6RDsnpyXJ1uYR3fXNbrAepxWOnhZo61voQiuEoHGKwG03YNc/3yHLN8LJkCEV/117hqwUGgaIgXaqliryelpstD6dB80= 23 | gem: sensu-plugins-mailer 24 | on: 25 | tags: true 26 | all_branches: true 27 | rvm: 2.3.0 28 | rvm: 2.4.1 29 | repo: sensu-plugins/sensu-plugins-mailer 30 | addons: 31 | code_climate: 32 | repo_token: 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | This project adheres to [Semantic Versioning](http://semver.org/). 3 | 4 | This CHANGELOG follows the format listed [here](https://github.com/sensu-plugins/community/blob/master/HOW_WE_CHANGELOG.md) 5 | 6 | ## [Unreleased] 7 | 8 | ## [4.0.0] - 2019-03-17 9 | ### Breaking Changes 10 | - Bump sensu-plugin version from `~> 2.0` to `~> 4.0` for Sensu 1.x to Sensu Go event conversion you can read the changelog entries for [4.0](https://github.com/sensu-plugins/sensu-plugin/blob/master/CHANGELOG.md#400---2018-02-17) and [3.0](https://github.com/sensu-plugins/sensu-plugin/blob/master/CHANGELOG.md#300---2018-12-04) (@asachs01) 11 | - drop support and testing for ruby 2.1 and 2.2 as they are EOL (@asachs01) 12 | 13 | ## [3.0.0] - 2018-12-07 14 | ### Breaking Changes 15 | - bumped dependency of `sensu-plugin` to 2.x you can read about it [here](https://github.com/sensu-plugins/sensu-plugin/blob/master/CHANGELOG.md#v145---2017-03-07) (@asachs01) 16 | 17 | ## [2.1.0] - 2018-11-01 18 | ### Added 19 | - handler-mailer.rb: add subject_template feature. With this option to can change the default subject with a template. 20 | 21 | ## [2.0.1] - 2018-01-31 22 | ### Fixed 23 | - handler-mailer.rb: emit an `unknown` with a helpful message when receiving an event `@event['contact']` with multiple objects in an array. This helps avoid confusion over using `contact` when you meant `contacts`. (@majormoses) 24 | 25 | ## [2.0.0] - 2017-10-21 26 | ### Breaking Change 27 | - handler-mailer.rb: emit an `unknown` with a helpful message when trying to configure `settings['contact']` with multiple objects. This helps avoid confusion over using `contact` when you meant `contacts`. (@majormoses) 28 | 29 | ### Added 30 | - ruby 2.4 testing in travis. (@majormoses) 31 | - handler-mailer.rb: added default key in description (@arthurlogilab) 32 | 33 | ### Fixed 34 | - PR template spell "Compatibility" correctly (@majormoses) 35 | - update changelog guideline location (@majormoses) 36 | 37 | ## [1.2.0] - 2017-06-24 38 | ### Added 39 | - handler-mailer.rb: add contact routing like Sensu Enterprise works (@stevenviola) 40 | 41 | ## [1.1.0] - 2017-06-01 42 | ### Fixed 43 | - handler-mailer.rb - revert the commit which makes email go to wrong addresses 44 | - handler-mailer.rb - change `json_config` to `json_config_name` for clarity 45 | and add documentation 46 | 47 | ## [1.0.0] - 2016-06-23 48 | ### Fixed 49 | - fix timeout deprecation for ruby 2.3.0 50 | - handler-mailer-mailgun.rb/handler-mailer-ses.rb: fix undefined local variable or method params error 51 | 52 | ### Removed 53 | - Support for Ruby 1.9.3; Added support for Ruby 2.3.0 54 | 55 | ### Changed 56 | - Update to Rubocop 0.40 and cleanup 57 | 58 | ## [0.3.1] - 2016-05-11 59 | ### Added 60 | - handler-mailer.rb: add smtp_use_tls setting to support SMTPS in Amazon SES 61 | 62 | ### Changed 63 | - Upgrade to rubocop 0.40 64 | 65 | ## [0.3.0] - 2016-04-23 66 | ### Fixed 67 | - Fix aws-ses gem dependency 68 | 69 | ### Added 70 | - handler-mailer.rb: add ability to build mailing list from client subscriptions 71 | 72 | ## [0.2.0] - 2016-03-17 73 | ### Added 74 | - Support for prefixing the email subject 75 | 76 | ### Fixed 77 | - handler-mailer.rb: Fix content type selection 78 | 79 | ## [0.1.5] - 2016-02-04 80 | ### Added 81 | - new certs 82 | 83 | ## [0.1.4] - 2016-02-04 84 | - Testing 85 | 86 | ## [0.1.3] - 2016-02-04 87 | - Testing 88 | 89 | ## [0.1.2] - 2015-12-30 90 | ### Fixed 91 | - Load correct mailgun gem in mailgun handler 92 | 93 | ## [0.1.1] - 2015-11-25 94 | ### Fixed 95 | - Fix check output 96 | 97 | ## [0.1.0] - 2015-11-17 98 | ### Added 99 | - Ability to use custom ERB template for mail message 100 | - Ability to specify a custom timeout interval for sending mail 101 | - Content type option 102 | - Add essential information to headers 103 | 104 | ### Fixed 105 | - Use correct mailgun gem 106 | - Correct password replacement 107 | 108 | ### Changed 109 | - Upgraded to rubocop 0.32.1 110 | 111 | ## [0.0.2] - 2015-07-14 112 | ### Changed 113 | - updated sensu-plugin gem to 1.2.0 114 | - updated documentation links in the README and CONTRIBUTING 115 | - puts deps in alpha order in the gemspec and rakefile 116 | 117 | ## 0.0.1 - 2015-06-04 118 | ### Added 119 | - initial release 120 | 121 | [Unreleased]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/3.0.0...HEAD 122 | [3.0.0]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/2.1.0...3.0.0 123 | [2.1.0]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/2.0.1...2.1.0 124 | [2.0.1]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/2.0.0...2.0.1 125 | [2.0.0]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/1.2.0...2.0.0 126 | [1.2.0]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/1.1.0...1.2.0 127 | [1.1.0]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/1.0.0...1.1.0 128 | [1.0.0]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.3.1...1.0.0 129 | [0.3.1]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.3.0...0.3.1 130 | [0.3.0]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.2.0...0.3.0 131 | [0.2.0]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/v0.1.5...0.2.0 132 | [0.1.5]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.1.4...v0.1.5 133 | [0.1.4]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.1.3...0.1.4 134 | [0.1.3]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.1.2...0.1.3 135 | [0.1.2]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.1.1...0.1.2 136 | [0.1.1]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.1.0...0.1.1 137 | [0.1.0]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.0.2...0.1.0 138 | [0.0.2]: https://github.com/sensu-plugins/sensu-plugins-mailer/compare/0.0.1...0.0.2 139 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | [Development Documentation](http://sensu-plugins.io/docs/developer_guidelines.html) 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Sensu-Plugins 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Sensu-Plugins-mailer 2 | 3 | [![Build Status](https://travis-ci.org/sensu-plugins/sensu-plugins-mailer.svg?branch=master)](https://travis-ci.org/sensu-plugins/sensu-plugins-mailer) 4 | [![Gem Version](https://badge.fury.io/rb/sensu-plugins-mailer.svg)](http://badge.fury.io/rb/sensu-plugins-mailer) 5 | [![Code Climate](https://codeclimate.com/github/sensu-plugins/sensu-plugins-mailer/badges/gpa.svg)](https://codeclimate.com/github/sensu-plugins/sensu-plugins-mailer) 6 | [![Test Coverage](https://codeclimate.com/github/sensu-plugins/sensu-plugins-mailer/badges/coverage.svg)](https://codeclimate.com/github/sensu-plugins/sensu-plugins-mailer) 7 | [![Dependency Status](https://gemnasium.com/sensu-plugins/sensu-plugins-mailer.svg)](https://gemnasium.com/sensu-plugins/sensu-plugins-mailer) 8 | 9 | ## Functionality 10 | 11 | ## Files 12 | * bin/handler-mailer-mailgun.rb 13 | * bin/handler-mailer-ses.rb 14 | * bin/handler-mailer.rb 15 | 16 | ## Usage 17 | 18 | The following three configuration variables must be set if you want mailer to use remote SMTP settings: 19 | 20 | smtp_address - defaults to "localhost" 21 | smtp_port - defaults to "25" 22 | smtp_domain - defaults to "localhost.localdomain" 23 | 24 | There is an optional subscriptions hash which can be added to your mailer.json file. This subscriptions hash allows you to define individual mail_to addresses for a given subscription. When the mailer handler runs it will check the clients subscriptions and build a mail_to string with the default mailer.mail_to address as well as any subscriptions the client subscribes to where a mail_to address is found. There can be N number of hashes inside of subscriptions but the key for a given hash inside of subscriptions must match a subscription name. 25 | 26 | Optionally, you can specify your own ERB template file to use for the message 27 | body. The order of precedence for templates is: command-line argument (-t), 28 | client config called "template", the mailer handler config, default. 29 | 30 | Optionally, you can specify your own ERB template file to use for the message 31 | subject. The order of precedence for templates is: command-line argument (-T), 32 | client config called "subject_template", the mailer handler config, default. 33 | 34 | ```json 35 | { 36 | "mailer": { 37 | "mail_from": "sensu@example.com", 38 | "mail_to": "monitor@example.com", 39 | "smtp_address": "smtp.example.org", 40 | "smtp_port": "25", 41 | "smtp_domain": "example.org", 42 | "template": "/optional/path/to/template.erb", 43 | "subject_template": "/optional/path/to/subject_template.erb", 44 | "subscriptions": { 45 | "subscription_name": { 46 | "mail_to": "teamemail@example.com" 47 | } 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | **handler-mailer-mailgun** 54 | ``` 55 | { 56 | "mailer-mailgun": { 57 | "mail_from": "sensu@example.com", 58 | "mail_to": "bob@example.com", 59 | "mg_apikey": "mailgunapikeygoeshere", 60 | "mg_domain": "mailgun.domain.com" 61 | } 62 | } 63 | ``` 64 | 65 | **handler-mailer-ses** 66 | ``` 67 | { 68 | "mailer-ses": { 69 | "mail_from": "sensu@example.com", 70 | "mail_to": "monitor@example.com", 71 | "aws_access_key": "myawsaccesskey", 72 | "aws_secret_key": "myawssecretkey", 73 | "aws_ses_endpoint": "email.us-east-1.amazonaws.com" 74 | } 75 | } 76 | ``` 77 | 78 | **handler-mailer** 79 | ``` 80 | { 81 | "mailer": { 82 | "admin_gui": "http://admin.example.com:8080/", 83 | "mail_from": "sensu@example.com", 84 | "mail_to": "monitor@example.com", 85 | "smtp_address": "smtp.example.org", 86 | "smtp_port": "25", 87 | "smtp_domain": "example.org" 88 | } 89 | } 90 | ``` 91 | By default, the handler will use `plain` as the SMTP authentication type, but you may also specify `"smtp_authentication": "ntlm"` for compatible servers, e.g. Microsoft Exchange. 92 | 93 | ### Contact Based Routing 94 | 95 | Optionally, this handler can use the same syntax as [Sensu Enterprise contact routing](https://sensuapp.org/docs/0.26/enterprise/contact-routing.html) for sending e-mails for particular checks or clients, in addition to the previous configuration. This is configured by declaring contacts: 96 | 97 | **support.json** 98 | ``` 99 | { 100 | "contacts": { 101 | "support": { 102 | "email": { 103 | "to": "support@sensuapp.com" 104 | } 105 | } 106 | } 107 | } 108 | ``` 109 | 110 | Then, in a check definition, you can specify a contact or an array of contacts which should be notified by e-mail: 111 | 112 | **example_check.json** 113 | ``` 114 | { 115 | "checks": { 116 | "example_check": { 117 | "command": "do_something.rb", 118 | "handler": "mailer", 119 | "contact": "support" 120 | } 121 | } 122 | } 123 | ``` 124 | 125 | Additionally, a client definition can specify a contact or an array of contacts to be notified of any check which alerts to the mailer handler. This is configured by specifying a contact value, or contacts array in the client.json configuration. 126 | 127 | ## Installation 128 | 129 | [Installation and Setup](http://sensu-plugins.io/docs/installation_instructions.html) 130 | 131 | Create a handler file in `/etc/sensu/conf.d` with the following content, replacing with your own configuration: 132 | 133 | ```json 134 | { 135 | "mailer" : { 136 | "admin_gui" : "http://localhost:3000", 137 | "mail_from": "from@email.com", 138 | "mail_to": "to@email.com", 139 | "delivery_method": "smtp", 140 | "smtp_address": "localhost", 141 | "smtp_port": "25", 142 | "smtp_domain": "localhost.local_domain", 143 | "smtp_enable_starttls_auto": "true", 144 | "smtp_username" : "username", 145 | "smtp_password" : "XXXXXXXX" 146 | }, 147 | "handlers": { 148 | "mailer": { 149 | "type": "pipe", 150 | "command": "/opt/sensu/embedded/bin/handler-mailer.rb" 151 | } 152 | } 153 | } 154 | ``` 155 | 156 | ## Notes 157 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'github/markup' 3 | require 'redcarpet' 4 | require 'rspec/core/rake_task' 5 | require 'rubocop/rake_task' 6 | require 'yard' 7 | require 'yard/rake/yardoc_task' 8 | 9 | args = [:spec, :make_bin_executable, :yard, :rubocop, :check_binstubs] 10 | 11 | YARD::Rake::YardocTask.new do |t| 12 | OTHER_PATHS = %w().freeze 13 | t.files = ['lib/**/*.rb', 'bin/**/*.rb', OTHER_PATHS] 14 | t.options = %w(--markup-provider=redcarpet --markup=markdown --main=README.md --files CHANGELOG.md) 15 | end 16 | 17 | RuboCop::RakeTask.new 18 | 19 | RSpec::Core::RakeTask.new(:spec) do |r| 20 | r.pattern = FileList['**/**/*_spec.rb'] 21 | end 22 | 23 | desc 'Make all plugins executable' 24 | task :make_bin_executable do 25 | `chmod -R +x bin/*` 26 | end 27 | 28 | desc 'Test for binstubs' 29 | task :check_binstubs do 30 | bin_list = Gem::Specification.load('sensu-plugins-mailer.gemspec').executables 31 | bin_list.each do |b| 32 | `which #{ b }` 33 | unless $CHILD_STATUS.success? 34 | puts "#{b} was not a binstub" 35 | exit 36 | end 37 | end 38 | end 39 | 40 | task default: args 41 | -------------------------------------------------------------------------------- /bin/handler-mailer-mailgun.rb: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby 2 | # encoding: UTF-8 3 | # mailer-mailgun.rb 4 | # 5 | # DESCRIPTION: 6 | # This handler formats alerts as mail and sends them off to a pre-defined recipient 7 | # using the Rackspace Mailgun service (http://www.rackspace.com/mailgun). 8 | # 9 | # OUTPUT: 10 | # Delivers email for events. 11 | # 12 | # PLATFORMS: 13 | # All 14 | # 15 | # DEPENDENCIES: 16 | # gem: sensu-plugin 17 | # gem: mailgun-ruby 18 | # 19 | # USAGE: 20 | # In mailer-mailgun.json, set the following values: 21 | # * mail_from: The from address that will appear in the email 22 | # * mail_to: The address of the recipent 23 | # * mg_apikey: The apikey of the Mailgun account 24 | # * mg_domain: The domain name that you have configured Mailgun to use 25 | # 26 | # LICENSE: 27 | # Chris Powell powellchristoph@gmail.com 28 | # Released under the same terms as Sensu (the MIT license); see LICENSE 29 | # for details. 30 | 31 | require 'sensu-handler' 32 | require 'mailgun' 33 | require 'timeout' 34 | 35 | class Mailer < Sensu::Handler 36 | option :json_config, 37 | description: 'Config Name', 38 | short: '-j JsonConfig', 39 | long: '--json_config JsonConfig', 40 | required: false, 41 | default: 'mailer-mailgun' 42 | 43 | def json_config 44 | @json_config ||= config[:json_config] 45 | end 46 | 47 | def short_name 48 | @event['client']['name'] + '/' + @event['check']['name'] 49 | end 50 | 51 | def action_to_string 52 | @event['action'].eql?('resolve') ? 'RESOLVED' : 'ALERT' 53 | end 54 | 55 | def handle 56 | params = { 57 | mail_to: settings[json_config]['mail_to'], 58 | mail_from: settings[json_config]['mail_from'], 59 | mg_apikey: settings[json_config]['mg_apikey'], 60 | mg_domain: settings[json_config]['mg_domain'], 61 | subject_prefix: settings[json_config]['subject_prefix'] 62 | } 63 | 64 | body = <<-BODY.gsub(/^ {14}/, '') 65 | #{@event['check']['output']} 66 | Host: #{@event['client']['name']} 67 | Timestamp: #{Time.at(@event['check']['issued'])} 68 | Address: #{@event['client']['address']} 69 | Check Name: #{@event['check']['name']} 70 | Command: #{@event['check']['command']} 71 | Status: #{@event['check']['status']} 72 | Occurrences: #{@event['occurrences']} 73 | BODY 74 | prefix_subject = params[:subject_prefix] + ' ' if params[:subject_prefix] 75 | subject = "#{prefix_subject}#{action_to_string} - #{short_name}: #{@event['check']['notification']}" 76 | 77 | mg_client = Mailgun::Client.new params[:mg_apikey] 78 | 79 | begin 80 | Timeout.timeout 10 do 81 | message_params = { 82 | from: params[:mail_from], 83 | to: params[:mail_to], 84 | subject: subject, 85 | text: body 86 | } 87 | 88 | mg_client.send_message params[:mg_domain], message_params 89 | 90 | puts 'mail -- sent alert for ' + short_name + ' to ' + params[:mail_to] 91 | end 92 | rescue Timeout::Error 93 | puts 'mail -- timed out while attempting to ' + @event['action'] + ' an incident -- ' + short_name 94 | end 95 | end 96 | end 97 | -------------------------------------------------------------------------------- /bin/handler-mailer-ses.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # Sensu Handler: mailer-ses 4 | # 5 | # This handler formats alerts as mails and sends them off to a pre-defined recipient. 6 | # Copyright 2013 github.com/foomatty 7 | # Copyright 2012 Pal-Kristian Hamre (https://github.com/pkhamre | http://twitter.com/pkhamre) 8 | # 9 | # Requires aws-ses gem 'gem install aws-ses' 10 | # 11 | # Released under the same terms as Sensu (the MIT license); see LICENSE 12 | # for details. 13 | 14 | require 'sensu-handler' 15 | require 'aws/ses' 16 | require 'timeout' 17 | 18 | class Mailer < Sensu::Handler 19 | option :json_config, 20 | description: 'Config Name', 21 | short: '-j JsonConfig', 22 | long: '--json_config JsonConfig', 23 | required: false, 24 | default: 'mailer-ses' 25 | 26 | def json_config 27 | @json_config ||= config[:json_config] 28 | end 29 | 30 | def short_name 31 | @event['client']['name'] + '/' + @event['check']['name'] 32 | end 33 | 34 | def action_to_string 35 | @event['action'].eql?('resolve') ? 'RESOLVED' : 'ALERT' 36 | end 37 | 38 | def handle 39 | params = { 40 | mail_to: settings[json_config]['mail_to'], 41 | mail_from: settings[json_config]['mail_from'], 42 | aws_access_key: settings[json_config]['aws_access_key'], 43 | aws_secret_key: settings[json_config]['aws_secret_key'], 44 | aws_ses_endpoint: settings[json_config]['aws_ses_endpoint'], 45 | subject_prefix: settings[json_config]['subject_prefix'] 46 | } 47 | 48 | body = <<-BODY.gsub(/^ {14}/, '') 49 | #{@event['check']['output']} 50 | Host: #{@event['client']['name']} 51 | Timestamp: #{Time.at(@event['check']['issued'])} 52 | Address: #{@event['client']['address']} 53 | Check Name: #{@event['check']['name']} 54 | Command: #{@event['check']['command']} 55 | Status: #{@event['check']['status']} 56 | Occurrences: #{@event['occurrences']} 57 | BODY 58 | prefix_subject = params[:subject_prefix] + ' ' if params[:subject_prefix] 59 | subject = "#{prefix_subject}#{action_to_string} - #{short_name}: #{@event['check']['notification']}" 60 | 61 | ses = AWS::SES::Base.new( 62 | access_key_id: params[:aws_access_key], 63 | secret_access_key: params[:aws_secret_key], 64 | server: params[:aws_ses_endpoint] 65 | ) 66 | 67 | begin 68 | Timeout.timeout 10 do 69 | ses.send_email( 70 | to: params[:mail_to], 71 | source: params[:mail_from], 72 | subject: subject, 73 | text_body: body 74 | ) 75 | 76 | puts 'mail -- sent alert for ' + short_name + ' to ' + params[:mail_to] 77 | end 78 | rescue Timeout::Error 79 | puts 'mail -- timed out while attempting to ' + @event['action'] + ' an incident -- ' + short_name 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /bin/handler-mailer.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # 3 | # Sensu Handler: mailer 4 | # 5 | # This handler formats alerts as mails and sends them off to a pre-defined recipient. 6 | # 7 | # Copyright 2012 Pal-Kristian Hamre (https://github.com/pkhamre | http://twitter.com/pkhamre) 8 | # 9 | # Released under the same terms as Sensu (the MIT license); see LICENSE 10 | # for details. 11 | 12 | # Note: The default mailer config is fetched from the predefined json config file which is "mailer.json" or any other 13 | # file defined using the "json_config" command line option. The mailing list could also be configured on a per client basis 14 | # by defining the "mail_to" attribute in the client config file. This will override the default mailing list where the 15 | # alerts are being routed to for that particular client. 16 | 17 | require 'sensu-handler' 18 | require 'mail' 19 | require 'timeout' 20 | require 'erubis' 21 | require 'set' 22 | require 'ntlm/smtp' 23 | 24 | # patch to fix Exim delivery_method: https://github.com/mikel/mail/pull/546 25 | # #YELLOW 26 | module ::Mail # rubocop:disable Style/ClassAndModuleChildren 27 | class Exim < Sendmail 28 | def self.call(path, arguments, _destinations, encoded_message) 29 | popen "#{path} #{arguments}" do |io| 30 | io.puts encoded_message.to_lf 31 | io.flush 32 | end 33 | end 34 | end 35 | end 36 | 37 | class Mailer < Sensu::Handler 38 | option :json_config_name, 39 | description: 'Name of the JSON Configuration block in Sensu (default: mailer)', 40 | short: '-j JsonConfig', 41 | long: '--json_config JsonConfig', 42 | required: false, 43 | default: 'mailer' 44 | 45 | option :template, 46 | description: 'Message template to use', 47 | short: '-t TemplateFile', 48 | long: '--template TemplateFile', 49 | required: false 50 | 51 | option :subject_template, 52 | description: 'Subject template to use', 53 | short: '-T TemplateFile', 54 | long: '--subject_template TemplateFile', 55 | required: false 56 | 57 | option :content_type, 58 | description: 'Content-type of message', 59 | short: '-c ContentType', 60 | long: '--content_type ContentType', 61 | required: false 62 | 63 | option :subject_prefix, 64 | description: 'Prefix message subjects with this string', 65 | short: '-s prefix', 66 | long: '--subject_prefix prefix', 67 | required: false 68 | 69 | # JSON configuration settings typically defined in the handler 70 | # file for mailer. JSON Config Name defaultly looks for a block 71 | # named 'mailer', as seen in the Installation step of the README 72 | # 73 | # @example 74 | # 75 | # ```json 76 | # { 77 | # "admin_gui": "http://localhost:3000", 78 | # "mail_from": "from@email.com", 79 | # "mail_to": "to@email.com", 80 | # "delivery_method": "smtp", 81 | # "smtp_address": "localhost", 82 | # "smtp_port": "25", 83 | # "smtp_domain": "localhost.local_domain", 84 | # "smtp_enable_starttls_auto": "true", 85 | # "smtp_username": "username", 86 | # "smtp_password": "XXXXXXXX" 87 | # } 88 | # ``` 89 | # 90 | # @return [Hash] 91 | def json_config_settings 92 | settings[config[:json_config_name]] 93 | end 94 | 95 | def short_name 96 | @event['client']['name'] + '/' + @event['check']['name'] 97 | end 98 | 99 | def action_to_string 100 | @event['action'].eql?('resolve') ? 'RESOLVED' : 'ALERT' 101 | end 102 | 103 | def prefix_subject 104 | if config[:subject_prefix] 105 | config[:subject_prefix] + ' ' 106 | elsif json_config_settings['subject_prefix'] 107 | json_config_settings['subject_prefix'] + ' ' 108 | else 109 | '' 110 | end 111 | end 112 | 113 | def status_to_string 114 | case @event['check']['status'] 115 | when 0 116 | 'OK' 117 | when 1 118 | 'WARNING' 119 | when 2 120 | 'CRITICAL' 121 | else 122 | 'UNKNOWN' 123 | end 124 | end 125 | 126 | def parse_content_type 127 | use = if config[:content_type] 128 | config[:content_type] 129 | elsif @event['check']['content_type'] 130 | @event['check']['content_type'] 131 | elsif json_config_settings['content_type'] 132 | json_config_settings['content_type'] 133 | else 134 | 'plain' 135 | end 136 | 137 | if use.casecmp('html').zero? 138 | 'text/html; charset=UTF-8' 139 | else 140 | 'text/plain; charset=ISO-8859-1' 141 | end 142 | end 143 | 144 | def raise_contact_is_array(src) 145 | msg = "you passed #{src} which is meant to be a string, " 146 | msg += 'if you need more than one contact you can use `contacts` to ' 147 | msg += 'configure multiple recipients' 148 | p msg 149 | exit 3 # unknown 150 | end 151 | 152 | def build_mail_to_list 153 | mail_to = Set.new 154 | mail_to.add(@event['client']['mail_to'] || json_config_settings['mail_to']) 155 | if json_config_settings.key?('subscriptions') && @event['check']['subscribers'] 156 | @event['check']['subscribers'].each do |sub| 157 | if json_config_settings['subscriptions'].key?(sub) 158 | mail_to.add(json_config_settings['subscriptions'][sub]['mail_to'].to_s) 159 | end 160 | end 161 | end 162 | if settings.key?('contact') && settings['contact'].is_a?(Array) 163 | raise_contact_is_array(settings['contact']) 164 | elsif settings.key?('contacts') 165 | all_contacts = [] 166 | %w(check client).each do |field| 167 | if @event[field].key?('contact') && @event[field]['contact'].is_a?(Array) 168 | raise_contact_is_array(@event[field]['contact']) 169 | elsif @event[field].key?('contact') 170 | all_contacts << @event[field]['contact'] 171 | end 172 | if @event[field].key?('contacts') 173 | all_contacts += @event[field]['contacts'] 174 | end 175 | end 176 | all_contacts.each do |sub| 177 | if settings['contacts'].key?(sub) 178 | mail_to.add(settings['contacts'][sub]['email']['to'].to_s) 179 | end 180 | end 181 | end 182 | mail_to.to_a.join(', ') 183 | end 184 | 185 | def subject_template 186 | return config[:subject_template] if config[:subject_template] 187 | return @event['check']['subject_template'] if @event['check']['subject_template'] 188 | return json_config_settings['subject_template'] if json_config_settings['subject_template'] 189 | nil 190 | end 191 | 192 | def build_subject 193 | template = if subject_template && File.readable?(subject_template) 194 | File.read(subject_template) 195 | else 196 | <<-SUBJECT.gsub(/^\s+/, '') 197 | <%= action_to_string %> - <%= short_name %>: <% if (@event['check']['notification'] != nil) then %><%= @event['check']['notification'] %><% else %><%= status_to_string %><% end %> 198 | SUBJECT 199 | end 200 | 201 | eruby = Erubis::Eruby.new(template) 202 | eruby.result(binding) 203 | end 204 | 205 | def message_template 206 | return config[:template] if config[:template] 207 | return @event['check']['template'] if @event['check']['template'] 208 | return json_config_settings['template'] if json_config_settings['template'] 209 | nil 210 | end 211 | 212 | def build_body 213 | admin_gui = json_config_settings['admin_gui'] || 'http://localhost:8080/' 214 | # try to redact passwords from output and command 215 | output = (@event['check']['output']).to_s.gsub(/(\s-p|\s-P|\s--password)(\s*\S+)/, '\1 ') 216 | command = (@event['check']['command']).to_s.gsub(/(\s-p|\s-P|\s--password)(\s*\S+)/, '\1 ') 217 | playbook = "Playbook: #{@event['check']['playbook']}" if @event['check']['playbook'] 218 | 219 | template = if message_template && File.readable?(message_template) 220 | File.read(message_template) 221 | else 222 | <<-BODY.gsub(/^\s+/, '') 223 | <%= output %> 224 | Admin GUI: <%= admin_gui %> 225 | Host: <%= @event['client']['name'] %> 226 | Timestamp: <%= Time.at(@event['check']['issued']) %> 227 | Address: <%= @event['client']['address'] %> 228 | Check Name: <%= @event['check']['name'] %> 229 | Command: <%= command %> 230 | Status: <%= status_to_string %> 231 | Occurrences: <%= @event['occurrences'] %> 232 | <%= playbook %> 233 | BODY 234 | end 235 | eruby = Erubis::Eruby.new(template) 236 | eruby.result(binding) 237 | end 238 | 239 | def handle 240 | body = build_body 241 | subject = "#{prefix_subject}#{build_subject}" 242 | 243 | content_type = parse_content_type 244 | mail_to = build_mail_to_list 245 | mail_from = json_config_settings['mail_from'] 246 | reply_to = json_config_settings['reply_to'] || mail_from 247 | 248 | delivery_method = json_config_settings['delivery_method'] || 'smtp' 249 | smtp_address = json_config_settings['smtp_address'] || 'localhost' 250 | smtp_port = json_config_settings['smtp_port'] || '25' 251 | smtp_domain = json_config_settings['smtp_domain'] || 'localhost.localdomain' 252 | 253 | smtp_username = json_config_settings['smtp_username'] || nil 254 | smtp_password = json_config_settings['smtp_password'] || nil 255 | smtp_authentication = json_config_settings['smtp_authentication'] || :plain 256 | smtp_use_tls = json_config_settings['smtp_use_tls'] || nil 257 | smtp_enable_starttls_auto = json_config_settings['smtp_enable_starttls_auto'] == 'false' ? false : true 258 | 259 | timeout_interval = json_config_settings['timeout'] || 10 260 | 261 | headers = { 262 | 'X-Sensu-Host' => (@event['client']['name']).to_s, 263 | 'X-Sensu-Timestamp' => Time.at(@event['check']['issued']).to_s, 264 | 'X-Sensu-Address' => (@event['client']['address']).to_s, 265 | 'X-Sensu-Check-Name' => (@event['check']['name']).to_s, 266 | 'X-Sensu-Status' => status_to_string.to_s, 267 | 'X-Sensu-Occurrences' => (@event['occurrences']).to_s 268 | } 269 | 270 | Mail.defaults do 271 | delivery_options = { 272 | address: smtp_address, 273 | port: smtp_port, 274 | domain: smtp_domain, 275 | openssl_verify_mode: 'none', 276 | tls: smtp_use_tls, 277 | enable_starttls_auto: smtp_enable_starttls_auto 278 | } 279 | 280 | unless smtp_username.nil? 281 | auth_options = { 282 | user_name: smtp_username, 283 | password: smtp_password, 284 | authentication: smtp_authentication 285 | } 286 | delivery_options.merge! auth_options 287 | end 288 | 289 | delivery_method delivery_method.intern, delivery_options 290 | end 291 | 292 | begin 293 | Timeout.timeout timeout_interval do 294 | Mail.deliver do 295 | to mail_to 296 | from mail_from 297 | reply_to reply_to 298 | subject subject 299 | body body 300 | headers headers 301 | content_type content_type 302 | end 303 | 304 | puts 'mail -- sent alert for ' + short_name + ' to ' + mail_to.to_s 305 | end 306 | rescue Timeout::Error 307 | puts 'mail -- timed out while attempting to ' + @event['action'] + ' an incident -- ' + short_name 308 | end 309 | end 310 | end 311 | -------------------------------------------------------------------------------- /certs/pvt_key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sensu-plugins/sensu-plugins-mailer/95c66074b32ad788488298713061815909db8fb8/certs/pvt_key -------------------------------------------------------------------------------- /lib/sensu-plugins-mailer.rb: -------------------------------------------------------------------------------- 1 | require 'sensu-plugins-mailer/version' 2 | -------------------------------------------------------------------------------- /lib/sensu-plugins-mailer/version.rb: -------------------------------------------------------------------------------- 1 | module SensuPluginsMailer 2 | module Version 3 | MAJOR = 4 4 | MINOR = 0 5 | PATCH = 0 6 | 7 | VER_STRING = [MAJOR, MINOR, PATCH].compact.join('.') 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /sensu-plugins-mailer.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path('../lib', __FILE__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | 4 | require 'date' 5 | require_relative 'lib/sensu-plugins-mailer' 6 | 7 | Gem::Specification.new do |s| 8 | s.authors = ['Sensu-Plugins and contributors'] 9 | s.date = Date.today.to_s 10 | s.description = 'Provides mail output for Sensu' 11 | s.email = '' 12 | s.executables = Dir.glob('bin/**/*.rb').map { |file| File.basename(file) } 13 | s.files = Dir.glob('{bin,lib}/**/*') + %w(LICENSE README.md CHANGELOG.md) 14 | s.homepage = 'https://github.com/sensu-plugins/sensu-plugins-mailer' 15 | s.license = 'MIT' 16 | s.metadata = { 'maintainer' => 'sensu-plugin', 17 | 'development_status' => 'active', 18 | 'production_status' => 'unstable - testing recommended', 19 | 'release_draft' => 'false', 20 | 'release_prerelease' => 'false' } 21 | s.name = 'sensu-plugins-mailer' 22 | s.platform = Gem::Platform::RUBY 23 | s.post_install_message = 'You can use the embedded Ruby by setting EMBEDDED_RUBY=true in /etc/default/sensu' 24 | s.require_paths = ['lib'] 25 | s.required_ruby_version = '>= 2.3.0' 26 | s.summary = 'Sensu plugins for mailer' 27 | s.test_files = s.files.grep(%r{^(test|spec|features)/}) 28 | s.version = SensuPluginsMailer::Version::VER_STRING 29 | 30 | s.add_runtime_dependency 'aws-ses', '0.6.0' 31 | s.add_runtime_dependency 'mail', '2.6.3' 32 | s.add_runtime_dependency 'mailgun-ruby', '1.0.3' 33 | s.add_runtime_dependency 'sensu-plugin', '~> 4.0' 34 | s.add_runtime_dependency 'erubis', '2.7.0' 35 | s.add_runtime_dependency 'ruby-ntlm', '0.0.4' 36 | 37 | s.add_development_dependency 'bundler', '~> 2.1' 38 | s.add_development_dependency 'codeclimate-test-reporter', '~> 1.0' 39 | s.add_development_dependency 'github-markup', '~> 3.0' 40 | s.add_development_dependency 'pry', '~> 0.10' 41 | s.add_development_dependency 'rake', '~> 12.3' 42 | s.add_development_dependency 'redcarpet', '~> 3.2' 43 | s.add_development_dependency 'rubocop', '~> 0.40.0' 44 | s.add_development_dependency 'rspec', '~> 3.4' 45 | s.add_development_dependency 'yard', '~> 0.8' 46 | end 47 | -------------------------------------------------------------------------------- /test/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'codeclimate-test-reporter' 2 | CodeClimate::TestReporter.start 3 | --------------------------------------------------------------------------------