module ExceptionNotifier::EmailNotifier::Mailer

Public Class Methods

extended(base) click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 33
def self.extended(base)
  base.class_eval do
    send(:include, ExceptionNotifier::BacktraceCleaner)

    # Append application view path to the ExceptionNotifier lookup context.
    append_view_path "#{File.dirname(__FILE__)}/views"

    def exception_notification(env, exception, options = {}, default_options = {})
      load_custom_views

      @env        = env
      @exception  = exception

      env_options = env['exception_notifier.options'] || {}
      @options    = default_options.merge(env_options).merge(options)

      @kontroller = env['action_controller.instance'] || MissingController.new
      @request    = ActionDispatch::Request.new(env)
      @backtrace  = exception.backtrace ? clean_backtrace(exception) : []
      @timestamp  = Time.current
      @sections   = @options[:sections]
      @data       = (env['exception_notifier.exception_data'] || {}).merge(options[:data] || {})
      @sections += %w[data] unless @data.empty?

      compose_email
    end

    def background_exception_notification(exception, options = {}, default_options = {})
      load_custom_views

      @exception = exception
      @options   = default_options.merge(options).symbolize_keys
      @backtrace = exception.backtrace || []
      @timestamp = Time.current
      @sections  = @options[:background_sections]
      @data      = options[:data] || {}
      @env = @kontroller = nil

      compose_email
    end

    private

    def compose_subject
      subject = @options[:email_prefix].to_s.dup
      subject << "(#{@options[:accumulated_errors_count]} times)" if @options[:accumulated_errors_count].to_i > 1
      subject << "#{@kontroller.controller_name}##{@kontroller.action_name}" if include_controller?
      subject << " (#{@exception.class})"
      subject << " #{@exception.message.inspect}" if @options[:verbose_subject]
      subject = EmailNotifier.normalize_digits(subject) if @options[:normalize_subject]
      subject.length > 120 ? subject[0...120] + '...' : subject
    end

    def include_controller?
      @kontroller && @options[:include_controller_and_action_names_in_subject]
    end

    def set_data_variables
      @data.each do |name, value|
        instance_variable_set("@#{name}", value)
      end
    end

    helper_method :inspect_object

    def truncate(string, max)
      string.length > max ? "#{string[0...max]}..." : string
    end

    def inspect_object(object)
      case object
      when Hash, Array
        truncate(object.inspect, 300)
      else
        object.to_s
      end
    end

    helper_method :safe_encode

    def safe_encode(value)
      value.encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
    end

    def html_mail?
      @options[:email_format] == :html
    end

    def compose_email
      set_data_variables
      subject = compose_subject
      name = @env.nil? ? 'background_exception_notification' : 'exception_notification'
      exception_recipients = maybe_call(@options[:exception_recipients])

      headers = {
        delivery_method: @options[:delivery_method],
        to: exception_recipients,
        from: @options[:sender_address],
        subject: subject,
        template_name: name
      }.merge(@options[:email_headers])

      mail = mail(headers) do |format|
        format.text
        format.html if html_mail?
      end

      mail.delivery_method.settings.merge!(@options[:mailer_settings]) if @options[:mailer_settings]

      mail
    end

    def load_custom_views
      return unless defined?(Rails) && Rails.respond_to?(:root)

      prepend_view_path Rails.root.nil? ? 'app/views' : "#{Rails.root}/app/views"
    end

    def maybe_call(maybe_proc)
      maybe_proc.respond_to?(:call) ? maybe_proc.call : maybe_proc
    end
  end
end

Public Instance Methods

background_exception_notification(exception, options = {}, default_options = {}) click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 60
def background_exception_notification(exception, options = {}, default_options = {})
  load_custom_views

  @exception = exception
  @options   = default_options.merge(options).symbolize_keys
  @backtrace = exception.backtrace || []
  @timestamp = Time.current
  @sections  = @options[:background_sections]
  @data      = options[:data] || {}
  @env = @kontroller = nil

  compose_email
end
compose_email() click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 121
def compose_email
  set_data_variables
  subject = compose_subject
  name = @env.nil? ? 'background_exception_notification' : 'exception_notification'
  exception_recipients = maybe_call(@options[:exception_recipients])

  headers = {
    delivery_method: @options[:delivery_method],
    to: exception_recipients,
    from: @options[:sender_address],
    subject: subject,
    template_name: name
  }.merge(@options[:email_headers])

  mail = mail(headers) do |format|
    format.text
    format.html if html_mail?
  end

  mail.delivery_method.settings.merge!(@options[:mailer_settings]) if @options[:mailer_settings]

  mail
end
compose_subject() click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 76
def compose_subject
  subject = @options[:email_prefix].to_s.dup
  subject << "(#{@options[:accumulated_errors_count]} times)" if @options[:accumulated_errors_count].to_i > 1
  subject << "#{@kontroller.controller_name}##{@kontroller.action_name}" if include_controller?
  subject << " (#{@exception.class})"
  subject << " #{@exception.message.inspect}" if @options[:verbose_subject]
  subject = EmailNotifier.normalize_digits(subject) if @options[:normalize_subject]
  subject.length > 120 ? subject[0...120] + '...' : subject
end
exception_notification(env, exception, options = {}, default_options = {}) click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 40
def exception_notification(env, exception, options = {}, default_options = {})
  load_custom_views

  @env        = env
  @exception  = exception

  env_options = env['exception_notifier.options'] || {}
  @options    = default_options.merge(env_options).merge(options)

  @kontroller = env['action_controller.instance'] || MissingController.new
  @request    = ActionDispatch::Request.new(env)
  @backtrace  = exception.backtrace ? clean_backtrace(exception) : []
  @timestamp  = Time.current
  @sections   = @options[:sections]
  @data       = (env['exception_notifier.exception_data'] || {}).merge(options[:data] || {})
  @sections += %w[data] unless @data.empty?

  compose_email
end
html_mail?() click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 117
def html_mail?
  @options[:email_format] == :html
end
include_controller?() click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 86
def include_controller?
  @kontroller && @options[:include_controller_and_action_names_in_subject]
end
inspect_object(object) click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 102
def inspect_object(object)
  case object
  when Hash, Array
    truncate(object.inspect, 300)
  else
    object.to_s
  end
end
load_custom_views() click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 145
def load_custom_views
  return unless defined?(Rails) && Rails.respond_to?(:root)

  prepend_view_path Rails.root.nil? ? 'app/views' : "#{Rails.root}/app/views"
end
maybe_call(maybe_proc) click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 151
def maybe_call(maybe_proc)
  maybe_proc.respond_to?(:call) ? maybe_proc.call : maybe_proc
end
safe_encode(value) click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 113
def safe_encode(value)
  value.encode('utf-8', invalid: :replace, undef: :replace, replace: '_')
end
set_data_variables() click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 90
def set_data_variables
  @data.each do |name, value|
    instance_variable_set("@#{name}", value)
  end
end
truncate(string, max) click to toggle source
# File lib/exception_notifier/email_notifier.rb, line 98
def truncate(string, max)
  string.length > max ? "#{string[0...max]}..." : string
end