bradpauly/griddler-mailgun

rspec feature | NoMethodError: undefined method `split' for nil:NilClass

Opened this issue · 5 comments

Hi All-

I'm trying to write a feature spec to test my email_processor.rb to simulate an email message being sent via HTTP POST request. My sample rspec looks like below:

require 'rails_helper'

RSpec.feature "EmailProcessors", type: :feature do
  def email_params
    {
      headers: 'Received: by 127.0.0.1 with SMTP...',
      to: 'thoughtbot <tb@example.com>',
      cc: 'CC <cc@example.com>',
      from: 'John Doe <someone@example.com>',
      subject: 'hello there',
      text: 'this is an email message',
      html: '<p>this is an email message</p>',
      charsets: '{"to":"UTF-8","html":"ISO-8859-1","subject":"UTF-8","from":"UTF-8","text":"ISO-8859-1"}',
      SPF: "pass"
    }
  end

  it 'POST new Email message' do
    # visit email_processor_path
    page.driver.post(email_processor_path, params: email_params)
    page.driver.status_code.should eql 200
  end
end

When trying to test this spec it will throw the following error as seen below. NoMethodError: undefined method `split' for nil:NilClass

EmailProcessors
  POST new Email message (FAILED - 1)

Failures:

  1) EmailProcessors POST new Email message
     Failure/Error: page.driver.post(email_processor_path, params: email_params)
     
     NoMethodError:
       undefined method `split' for nil:NilClass
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/griddler-mailgun-1.0.3/lib/griddler/mailgun/adapter.rb:39:in `to_recipients'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/griddler-mailgun-1.0.3/lib/griddler/mailgun/adapter.rb:17:in `normalize_params'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/griddler-mailgun-1.0.3/lib/griddler/mailgun/adapter.rb:12:in `normalize_params'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/griddler-1.4.0/app/controllers/griddler/emails_controller.rb:17:in `normalized_params'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/griddler-1.4.0/app/controllers/griddler/emails_controller.rb:3:in `create'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/warden-1.2.7/lib/warden/manager.rb:36:in `block in call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/warden-1.2.7/lib/warden/manager.rb:35:in `catch'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/warden-1.2.7/lib/warden/manager.rb:35:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/etag.rb:24:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/conditionalget.rb:38:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/head.rb:13:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/session/abstract/id.rb:225:in `context'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/session/abstract/id.rb:220:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/railties-4.2.4/lib/rails/rack/logger.rb:38:in `call_app'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/railties-4.2.4/lib/rails/rack/logger.rb:20:in `block in call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/railties-4.2.4/lib/rails/rack/logger.rb:20:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/request_store-1.3.1/lib/request_store/middleware.rb:9:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/methodoverride.rb:22:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/runtime.rb:18:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/lock.rb:17:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/sendfile.rb:113:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/railties-4.2.4/lib/rails/engine.rb:518:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/railties-4.2.4/lib/rails/application.rb:165:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/urlmap.rb:66:in `block in call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/urlmap.rb:50:in `each'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-1.6.8/lib/rack/urlmap.rb:50:in `call'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-test-0.6.3/lib/rack/mock_session.rb:30:in `request'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-test-0.6.3/lib/rack/test.rb:244:in `process_request'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/rack-test-0.6.3/lib/rack/test.rb:67:in `post'
     # /Users/user/.rvm/gems/ruby-2.3.1/gems/capybara-2.16.0/lib/capybara/rack_test/driver.rb:101:in `post'
     # ./spec/features/email_processors_spec.rb:20:in `block (2 levels) in <top (required)>'

Finished in 0.18955 seconds (files took 11.33 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/features/email_processors_spec.rb:18 # EmailProcessors POST new Email message

Gemfile:

gem 'griddler-mailgun'

Gemfile.lock

    griddler (1.4.0)
      htmlentities
      rails (>= 3.2.0)
    griddler-mailgun (1.0.3)
      griddler

Any advice what I might be doing wrong or how to effectively test the email_processor.rb would be much appreciated. Cheers.

Hey @zeknox, I just ran into a similar problem. Digging through the source code revealed that the griddler-mailgun gem expects the params to be formatted very specifically.

Here's the relevant params you provided:

headers: 'Received: by 127.0.0.1 with SMTP...',
to: 'thoughtbot <tb@example.com>',
cc: 'CC <cc@example.com>',
from: 'John Doe <someone@example.com>',

Here's the keys griddler-mailgun expects:

headers: '...',
"To" => 'thoughtbot <tb@example.com>,
"Cc" => 'CC <cc@example.com',

etc.

To be explicit, the to, from, cc and bcc fields all expect capitalized values.

You can explore exactly what keys are expected and how they ought to be formatted here: https://github.com/bradpauly/griddler-mailgun/blob/master/lib/griddler/mailgun/adapter.rb#L37

I spent a while wrestling with this exact same problem. I'll have a PR in to update the README, or maybe raise a specific error, depending on @bradpauly's preference.

For now, I wanted to document this for others who might come here experiencing the same problem.

I think I found the answer of the internet standards for field capitalization.

From https://tools.ietf.org/html/rfc2821#section-2.4:

Verbs and argument values (e.g., "TO:" or "to:" in the RCPT command and extension name keywords) are not case sensitive, with the sole exception in this specification of a mailbox local-part (SMTP Extensions may explicitly specify case-sensitive elements)

The "mailbox local-part" would be smith in smith@company.com; RFC281 says that smith@email.com is distinct from Smith@email.com, but goes on to say

However, exploiting the case sensitivity of mailbox local-parts impedes interoperability and is discouraged.

Ah. RFC 822, section 3.4.7 CASE INDEPENDENCE:

Except as noted, alphabetic strings may be represented in any combination of upper and lower case.

When matching any other syntactic unit, case is to be ignored. For example, the field-names "From", "FROM", "from", and even "FroM" are semantically equal and should all be treated identically.

To that end, I'll open up a PR that makes the keys case-insensitive.

@josh-works sorry I haven't gotten to this yet and thanks for the update. I'll be able to give it some attention next week.

@zeknox are you receiving a lowercase to param from a mailgun route? I believe its usually present in the message-headers JSON. It isn't one of the documented params here: https://documentation.mailgun.com/en/latest/user_manual.html#routes

I think it might still be worth merging the PR from @josh-works, but I'm hesitant if it isn't a documented param and the change might only satisfy the test.

Ah, I think mailgun does send an uppercase To params, but it isn't documented. 🤔