Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datadog log formatting #1

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ rvm:
- 2.0
- 2.1
- 2.2
- 2.3
- 2.4
- 2.5
- 2.6
- 2.7
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,26 @@ Once you have correctly configured Mandrill, you can go ahead and delete this co
[Adding Routes]: http://help.mandrill.com/entries/21699367-Inbound-Email-Processing-Overview

#### Allowing domains without SPF configured
Sometimes, due to circumstances outside our control, a domain may not have SPF set up. In those cases, you can set the adapter to pass results to your email processor.
Sometimes, due to circumstances outside our control, a domain may not have SPF set up or configured incorrectly.

If that is causing you to miss emails; you may configure the adapter to allow those results through to your applications email processor.

Please see [RFC4408 Section 2.5](https://tools.ietf.org/html/rfc4408#section-2.5) to determine whether your particular use case conforms to the SPF standard.
```
Griddler::Mandrill::Adapter.allow_spf_none = true
# Allow messages from domains without SPF configured
Griddler::Mandrill.spf_allow.add(:none)

# Allow messages from domains where SPF is erroring temporarily
Griddler::Mandrill.spf_allow.add(:temperror)

# Allow messages from domains where SPF is erroring permanently
Griddler::Mandrill.spf_allow.add(:permerror)

# Allow messages from domains where SPF is soft-failing
Griddler::Mandrill.spf_allow.add(:softfail)

# Allow messages from domains where SPF is failing
Griddler::Mandrill.spf_allow.add(:fail)
```

## Credits
Expand Down
1 change: 1 addition & 0 deletions griddler-mandrill.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ Gem::Specification.new do |spec|

spec.add_development_dependency 'rspec'
spec.add_development_dependency 'rake'
spec.add_development_dependency 'yard'
spec.add_development_dependency 'activesupport'
end
13 changes: 12 additions & 1 deletion lib/griddler/mandrill.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
require 'griddler'
require 'griddler/mandrill/version'
require 'griddler/mandrill/adapter'
require 'griddler/mandrill/logging'
require 'griddler/mandrill/spf_filter'
require 'griddler/mandrill/version'

Griddler.adapter_registry.register(:mandrill, Griddler::Mandrill::Adapter)

module Griddler
module Mandrill

def self.spf_allow
@spf_allow ||= Set.new([:pass, :neutral])
end
end
end
29 changes: 28 additions & 1 deletion lib/griddler/mandrill/adapter.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'tempfile'
module Griddler
module Mandrill
class Adapter
Expand Down Expand Up @@ -29,8 +30,23 @@ def event_passes_spf?(event)
end

def normalize_params
events.each do |event|
Rails.logger.warn(logger: "Griddler::Mandrill::Adapter",
message: "Inbound email received",
to: recipients(:to, event),
cc: recipients(:cc, event),
bcc: resolve_bcc(event),
headers: event[:headers],
from: full_email([event[:from_email], event[:from_name]]),
subject: event[:subject],
email: event[:email], # the email address where Mandrill received the message
spf: event[:spf],
spam_report: event[:spam_report]
)
end

events.select do |event|
event_passes_spf?(event)
spf_filter.passes?(event)
end.map do |event|
{
to: recipients(:to, event),
Expand All @@ -49,6 +65,13 @@ def normalize_params
end
end

protected

# @return [Logger]
def logger
Logging.logger
end

private

attr_reader :params
Expand Down Expand Up @@ -105,6 +128,10 @@ def create_tempfile(attachment)
tempfile.rewind
tempfile
end

def spf_filter
@spf_filter ||= SpfFilter.new
end
end
end
end
28 changes: 28 additions & 0 deletions lib/griddler/mandrill/logging.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Griddler
module Mandrill
module Logging
# The default logger discards all message; as we do not want
# to start clogging up existing users logs.
def self.logger
@logger ||= NullLogger.new(STDOUT)
end

# Set your application's logger
# @example In a Rails initializer:
# Griddler::Mandrill::Logging.logger = Rails.logger
# @example Logging to the same location Rails does, but at a different log level
# Griddler::Mandrill::Logging.logger = ActiveSupport::Logger.new(Rails.logger.instance_variable_get("@logdev"), level: :debug)
def self.logger=(logger)
@logger = logger
end

# A logger which discards messages
class NullLogger < Logger
# Overload the Logger#add method as this is where the #info/#warn/#error methods
# send their messags to the logging subsystem.
def add(*_arguments)
end
end
end
end
end
22 changes: 22 additions & 0 deletions lib/griddler/mandrill/spf_filter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Griddler
module Mandrill
# Checks whether an events SPF result matches the configured preferences
class SpfFilter
attr_accessor :allow

def initialize(allow: default_allow_options)
self.allow = allow
end

def passes?(event)
allow.include?((event.dig(:spf, :result).presence || 'none').to_sym)
end

private

def default_allow_options
Griddler::Mandrill.spf_allow.dup
end
end
end
end
Binary file added spec/fixtures/photo1.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added spec/fixtures/photo2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 114 additions & 3 deletions spec/griddler/mandrill/adapter_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'spec_helper'
require 'base64'

describe Griddler::Mandrill::Adapter do
it 'registers itself with griddler' do
Expand Down Expand Up @@ -118,6 +119,33 @@
end
end

describe "when the spf record is nil" do
before do
@params = params_hash
@params.first[:msg][:spf] = { result: nil, detail: nil }
end

it 'does not include the emails without spf results by default' do
params = default_params(@params)
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).to be_empty
end

context 'when the adapter is configured to allow none' do
before do
Griddler::Mandrill.spf_allow.add(:none)
end
after do
Griddler::Mandrill.spf_allow.delete(:none)
end
it 'includes the message' do
params = default_params(@params)
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).not_to be_empty
end
end
end

describe 'when the spf record is none' do
before do
@params = params_hash
Expand All @@ -132,10 +160,10 @@

context 'when the adapter is configured to allow none' do
before do
Griddler::Mandrill::Adapter.allow_spf_none = true
Griddler::Mandrill.spf_allow.add(:none)
end
after do
Griddler::Mandrill::Adapter.allow_spf_none = false
Griddler::Mandrill.spf_allow.delete(:none)
end
it 'includes the message' do
params = default_params(@params)
Expand All @@ -151,11 +179,80 @@
@params.first[:msg][:spf] = { result: 'softfail', detail: 'domain owner discourages use of this host' }
end

it "doesn't include emails that have failed the SPF test" do
it "does not include the emails by default" do
params = default_params(@params)
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).to be_empty
end

context 'when the adapter is configured to allow softfail' do
before do
Griddler::Mandrill.spf_allow.add(:softfail)
end
after do
Griddler::Mandrill.spf_allow.delete(:softfail)
end
it 'includes the message' do
params = default_params(@params)
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).not_to be_empty
end
end
end

describe 'when the spf record is temperror' do
before do
@params = params_hash
@params.first[:msg][:spf] = { result: 'temperror', detail: 'sender SPF temperror' }
end

it "drops the email by default" do
params = default_params(@params)
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).to be_empty
end

context 'when the adapter is configured to allow temperror' do
before do
Griddler::Mandrill.spf_allow.add(:temperror)
end
after do
Griddler::Mandrill.spf_allow.delete(:temperror)
end

it 'includes the message' do
params = default_params(@params)
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).not_to be_empty
end
end
end

describe 'when the spf record is permerror' do
before do
@params = params_hash
@params.first[:msg][:spf] = { result: 'permerror', detail: 'sender SPF permerror' }
end

it "drops the email by default" do
params = default_params(@params)
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).to be_empty
end

context 'when the adapter is configured to allow permerror' do
before do
Griddler::Mandrill.spf_allow.add(:permerror)
end
after do
Griddler::Mandrill.spf_allow.delete(:permerror)
end
it 'includes the message' do
params = default_params(@params)
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).not_to be_empty
end
end
end

describe 'when the spf record is fail' do
Expand All @@ -169,6 +266,20 @@
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).to be_empty
end

context 'when the adapter is configured to allow fail' do
before do
Griddler::Mandrill.spf_allow.add(:fail)
end
after do
Griddler::Mandrill.spf_allow.delete(:fail)
end
it 'includes the message' do
params = default_params(@params)
normalized_params = Griddler::Mandrill::Adapter.normalize_params(params)
expect(normalized_params).not_to be_empty
end
end
end

describe 'when the spf record is neutral' do
Expand Down
8 changes: 8 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'griddler'
require 'griddler/testing'
require 'griddler/mandrill'
require 'action_dispatch'
Expand All @@ -10,6 +11,13 @@
config.include Griddler::Testing
end


class Griddler::Testing::UploadedImage
def fixture_file
cwd = File.expand_path File.dirname(__FILE__)
File.new(File.join(cwd, 'fixtures', @name))
end
end
RSpec::Matchers.define :be_normalized_to do |expected|
failure_message do |actual|
message = ""
Expand Down