require 'erb' require 'tilt/erb' require 'tuktuk' module Snails class Mailer @queue = :emails def initialize(opts) cwd = Pathname.new(Dir.pwd) 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 @from_email = opts[:from] or raise ":from required" @base_subject = opts[:base_subject] || '' @views = opts[:views] || cwd.join('lib', 'views') @logfile = opts[:logfile] || cwd.join('log', 'mailer.log') end def email(name, &block) define_singleton_method(name) do |*args| instance_exec(*args, &block) end 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 ||= Logger.new(@logfile) end def send_email(to:, subject:, body:, from: nil, html: nil) raise "No recipient given for mail: #{subject}!" if to.blank? message = { to: to, from: from || @from_email, subject: @base_subject + subject, body: body.is_a?(Symbol) ? render(body) : body } if html message[:html_body] = html.is_a?(Symbol) ? render(html) : html end logger.info "[#{to}] Delivering: #{subject}" resp, email = Tuktuk.deliver(message) if Snails.env.production? if resp.is_a?(Tuktuk::Bounce) logger.info "[#{to}] Email bounced! [#{resp.code}] #{resp.message}" end return resp, email end end end