require 'erb' require 'tilt/erb' require 'tuktuk' require 'snails' module Snails class Mailer include Snails::SimpleFormat Time.include(Snails::RelativeTime) unless Time.instance_methods.include?(:relative) @queue = :emails def initialize(opts) mail_config = (opts[:smtp] || opts[:mail]) or raise ":smtp options missing" if key = mail_config.dig(:dkim, :private_key) and File.exist?(key) mail_config[:dkim][:private_key] = IO.read(key) elsif mail_config[:dkim] puts "Private key for DKIM not found! Disabling..." mail_config.delete(:dkim) end Tuktuk.options = mail_config @debug = mail_config[:debug] @from_email = opts[:from] or raise ":from required" @base_subject = opts[:base_subject] || '' @views = opts[:views] || Snails.root.join('lib', 'views') @logfile = opts[:logfile] # || Snails.root.join('log', 'mailer.log') end def email(name, &block) define_singleton_method(name) do |*args| instance_exec(*args, &block) end end def helpers(&block) instance_eval(&block) end def perform(method, *args) send(method, *args) end # e.g. Notifier.queue(:some_notification, @project, "arg1") def queue(method, obj, *args) return unless Snails.env.production? Resque.enqueue(self, method, obj.id, *args) end def send_error(to: @from_email, err:, env:, params: {}) @exception, @env, @params = err, env, params @url = "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']}" subject = "#{@url} :: (#{@exception.class}) \"#{@exception.message}\"" content = %{ A <%= @exception.class %> occurred in <%= @url %>: ----------------- <%= @exception.message %> <%= @exception.backtrace.join("\n") %> ----------------- - Request : <%= @url %> - Parameters : <%= @params.inspect %> - IP address : <%= @env['REMOTE_ADDR'] %> - User agent : <%= @env['HTTP_USER_AGENT'] %> - Process : <%= $$ %> - Server : <%= `hostname -s`.chomp %> ----------------- }.strip send_email(to: to, subject: subject, body: content) end private def render(view) template = File.read(File.join(@views, "#{view}.erb")) ERB.new(template).result(binding) end def partial(name) partial_name = name.to_s["/"] ? name.to_s.reverse.sub("/", "_/").reverse : "_#{name}" render partial_name end def logger @logger ||= @logfile ? Logger.new(@logfile) : Snails.logger end def send_email(from: nil, to:, subject:, body: nil, template: nil, html_body: nil, html_template: nil) raise "No recipient given for mail: #{subject}!" if to.blank? message = { to: to, from: from || @from_email, subject: @base_subject + subject } if body or template message[:body] = template ? render(template) : body end if html_body or html_template message[:html_body] = html_template ? render(html_template) : html_body end logger.info "[#{to}] Delivering: #{subject}" debug = @debug.nil? ? !Snails.env.production? : @debug # if debug isn't set, determine based on env resp, email = Tuktuk.deliver(message, debug: debug) if resp.is_a?(Tuktuk::Bounce) logger.info "[#{to}] Email bounced! [#{resp.code}] #{resp.message}" end return resp, email end end end