├── .gitignore ├── .travis.yml ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── lib ├── sidekiq_mailer.rb └── sidekiq_mailer │ ├── proxy.rb │ ├── version.rb │ └── worker.rb ├── sidekiq_mailer.gemspec └── test ├── sidekiq_mailer_test.rb └── test_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | .rvmrc 7 | Gemfile.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | doc/ 12 | lib/bundler/man 13 | pkg 14 | rdoc 15 | spec/reports 16 | test/tmp 17 | test/version_tmp 18 | tmp 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | env: 2 | - "RAILS_VERSION=3.1.0" 3 | - "RAILS_VERSION=3.2.0" 4 | - "RAILS_VERSION=4.0.0" 5 | rvm: 6 | - 1.9.3 7 | - 2.0.0 8 | - jruby-19mode 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in sidekiq_mailer.gemspec 4 | gemspec 5 | 6 | rails_version = ENV["RAILS_VERSION"] || "default" 7 | 8 | rails = case rails_version 9 | when "master" 10 | {github: "rails/rails"} 11 | when "default" 12 | "~> 3.2.0" 13 | else 14 | "~> #{rails_version}" 15 | end 16 | 17 | gem 'actionmailer', rails -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Anderson Dias 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sidekiq::Mailer 2 | 3 | Sidekiq::Mailer adds to your ActionMailer classes the ability to send mails asynchronously. 4 | 5 | ## Usage 6 | 7 | If you want to make a specific mailer to work asynchronously just include Sidekiq::Mailer module: 8 | 9 | class MyMailer < ActionMailer::Base 10 | include Sidekiq::Mailer 11 | 12 | def welcome(to) 13 | ... 14 | end 15 | end 16 | 17 | Now every deliver you make with MyMailer will be asynchronous. 18 | 19 | # Queues the mail to be sent asynchronously by sidekiq 20 | MyMailer.welcome('your@email.com').deliver 21 | 22 | The default queue used by Sidekiq::Mailer is 'mailer'. So, in order to send mails with sidekiq you need to start a worker using: 23 | 24 | sidekiq -q mailer 25 | 26 | If you want to skip sidekiq you should use the 'deliver!' method: 27 | 28 | # Mail will skip sidekiq and will be sent synchronously 29 | MyMailer.welcome('your@email.com').deliver! 30 | 31 | By default Sidekiq::Mailer will retry to send an email if it failed. But you can [override sidekiq options](https://github.com/andersondias/sidekiq_mailer/wiki/Overriding-sidekiq-options) in your mailer. 32 | 33 | ## Installation 34 | 35 | Add this line to your application's Gemfile: 36 | 37 | gem 'sidekiq_mailer' 38 | 39 | And then execute: 40 | 41 | $ bundle 42 | 43 | Or install it yourself as: 44 | 45 | $ gem install sidekiq_mailer 46 | 47 | ## Testing 48 | 49 | Delayed e-mails is an awesome thing in production environments, but for e-mail specs/tests in testing environments it can be a mess causing specs/tests to fail because the e-mail haven't been sent directly. Therefore you can configure what environments that should be excluded like so: 50 | 51 | # config/initializers/sidekiq_mailer.rb 52 | Sidekiq::Mailer.excluded_environments = [:test, :cucumber] 53 | 54 | ## Contributing 55 | 56 | 1. Fork it 57 | 2. Create your feature branch (`git checkout -b my-new-feature`) 58 | 3. Commit your changes (`git commit -am 'Added some feature'`) 59 | 4. Push to the branch (`git push origin my-new-feature`) 60 | 5. Create new Pull Request 61 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rake 2 | # encoding: UTF-8 3 | require "bundler/gem_tasks" 4 | require 'rake/testtask' 5 | 6 | Rake::TestTask.new do |t| 7 | t.libs << 'lib' 8 | t.libs << 'test' 9 | t.pattern = 'test/**/*_test.rb' 10 | t.verbose = true 11 | end 12 | 13 | desc "Run tests" 14 | task :default => :test -------------------------------------------------------------------------------- /lib/sidekiq_mailer.rb: -------------------------------------------------------------------------------- 1 | require 'sidekiq_mailer/version' 2 | require 'sidekiq_mailer/worker' 3 | require 'sidekiq_mailer/proxy' 4 | 5 | module Sidekiq 6 | module Mailer 7 | @@excluded_environments = nil 8 | 9 | def self.excluded_environments=(envs) 10 | @@excluded_environments = [*envs].map { |e| e && e.to_sym } 11 | end 12 | 13 | def self.excluded_environments 14 | @@excluded_environments ||= [] 15 | end 16 | 17 | def self.current_env 18 | if defined?(Rails) 19 | ::Rails.env 20 | else 21 | ENV['RAILS_ENV'].to_s 22 | end 23 | end 24 | 25 | def self.excludes_current_environment? 26 | !ActionMailer::Base.perform_deliveries || (excluded_environments && excluded_environments.include?(current_env.to_sym)) 27 | end 28 | 29 | def self.included(base) 30 | base.extend(ClassMethods) 31 | base.class_attribute :sidekiq_options_hash 32 | end 33 | 34 | module ClassMethods 35 | ## 36 | # Allows customization for this type of Worker. 37 | # Legal options: 38 | # 39 | # :queue - use a named queue for this Worker, default 'mailer' 40 | # :retry - enable the RetryJobs middleware for this Worker, default *true* 41 | # :timeout - timeout the perform method after N seconds, default *nil* 42 | # :backtrace - whether to save any error backtrace in the retry payload to display in web UI, 43 | # can be true, false or an integer number of lines to save, default *false* 44 | def sidekiq_options(opts={}) 45 | self.sidekiq_options_hash = get_sidekiq_options.merge(stringify_keys(opts || {})) 46 | end 47 | 48 | DEFAULT_OPTIONS = { 'retry' => true, 'queue' => 'mailer' } 49 | 50 | def get_sidekiq_options # :nodoc: 51 | self.sidekiq_options_hash ||= DEFAULT_OPTIONS 52 | end 53 | 54 | def stringify_keys(hash) # :nodoc: 55 | hash.keys.each do |key| 56 | hash[key.to_s] = hash.delete(key) 57 | end 58 | hash 59 | end 60 | 61 | def method_missing(method_name, *args) 62 | if action_methods.include?(method_name.to_s) 63 | Sidekiq::Mailer::Proxy.new(self, method_name, *args) 64 | else 65 | super 66 | end 67 | end 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /lib/sidekiq_mailer/proxy.rb: -------------------------------------------------------------------------------- 1 | class Sidekiq::Mailer::Proxy 2 | delegate :to_s, :to => :actual_message 3 | 4 | def initialize(mailer_class, method_name, *args) 5 | @mailer_class = mailer_class 6 | @method_name = method_name 7 | *@args = *args 8 | end 9 | 10 | def actual_message 11 | @actual_message ||= @mailer_class.send(:new, @method_name, *@args).message 12 | end 13 | 14 | def deliver 15 | return deliver! if Sidekiq::Mailer.excludes_current_environment? 16 | Sidekiq::Mailer::Worker.client_push(to_sidekiq) 17 | end 18 | 19 | def excluded_environment? 20 | Sidekiq::Mailer.excludes_current_environment? 21 | end 22 | 23 | def deliver! 24 | actual_message.deliver 25 | end 26 | 27 | def method_missing(method_name, *args) 28 | actual_message.send(method_name, *args) 29 | end 30 | 31 | def to_sidekiq 32 | params = { 33 | 'class' => Sidekiq::Mailer::Worker, 34 | 'args' => [@mailer_class.to_s, @method_name, @args] 35 | } 36 | params.merge(@mailer_class.get_sidekiq_options) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/sidekiq_mailer/version.rb: -------------------------------------------------------------------------------- 1 | module Sidekiq 2 | module Mailer 3 | VERSION = "0.0.8" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/sidekiq_mailer/worker.rb: -------------------------------------------------------------------------------- 1 | class Sidekiq::Mailer::Worker 2 | include Sidekiq::Worker 3 | 4 | def perform(mailer_class, action, params) 5 | mailer_class.constantize.send(action, *params).deliver! 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /sidekiq_mailer.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require File.expand_path('../lib/sidekiq_mailer/version', __FILE__) 3 | 4 | Gem::Specification.new do |gem| 5 | gem.authors = ["Anderson Dias"] 6 | gem.email = ["andersondaraujo@gmail.com"] 7 | gem.description = %q{Asynchronous mail delivery using sidekiq} 8 | gem.summary = %q{Turning ActiveMailer deliveries asynchronous using the power of sidekiq} 9 | gem.homepage = "http://github.com/andersondias/sidekiq_mailer" 10 | gem.license = "MIT" 11 | 12 | gem.files = `git ls-files`.split($\) 13 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } 14 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) 15 | gem.name = "sidekiq_mailer" 16 | gem.require_paths = ["lib"] 17 | gem.version = Sidekiq::Mailer::VERSION 18 | 19 | gem.add_dependency("activesupport", ">= 3.0") 20 | gem.add_dependency("actionmailer", ">= 3.0") 21 | gem.add_dependency("sidekiq", ">= 2.3") 22 | gem.add_development_dependency('rake') 23 | end 24 | -------------------------------------------------------------------------------- /test/sidekiq_mailer_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class BasicMailer < ActionMailer::Base 4 | include Sidekiq::Mailer 5 | 6 | default :from => "from@example.org", :subject => "Subject" 7 | 8 | def welcome(to) 9 | mail(to: to) do |format| 10 | format.text { render :text => "Hello Mikel!" } 11 | format.html { render :text => "