3

Ive checked many posts about it and still, cant find the solution..i thought that its working in deployment but no, those emails werent sent..i was just getting them in the console.

Ive checked my sendgrid credentials, i added global variables with dotenv so maybe something is wrong with my code..

I also tried that code to send email directly:

require 'sendgrid-ruby'
include SendGrid

from = Email.new(email: 'test@example.com')
to = Email.new(email: 'test@example.com')
subject = 'Sending with SendGrid is Fun'
content = Content.new(type: 'text/plain', value: 'and easy to do anywhere, 
even with Ruby')
mail = Mail.new(from, subject, to, content)

sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])
response = sg.client.mail._('send').post(request_body: mail.to_json)
puts response.status_code
puts response.body
puts response.parsed_body
puts response.headers

with no luck:

puts response.status_code
400
 => nil 
2.3.4 :016 > puts response.body
{"errors":[{"message":"Invalid type. Expected: object, given: string.","field":"(root)","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#-Request-Body-Parameters"}]}
 => nil 
 puts response.parsed_body
{:errors=>[{:message=>"Invalid type. Expected: object, given: string.", :field=>"(root)", :help=>"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#-Request-Body-Parameters"}]}
2.3.4 :017 > puts response.headers
{"server"=>["nginx"], "date"=>["Wed, 04 Apr 2018 17:43:43 GMT"], "content-type"=>["application/json"], "content-length"=>["191"], "connection"=>["close"], "access-control-allow-origin"=>["https://sendgrid.api-docs.io"], "access-control-allow-methods"=>["POST"], "access-control-allow-headers"=>["Authorization, Content-Type, On-behalf-of, x-sg-elas-acl"], "access-control-max-age"=>["600"], "x-no-cors-reason"=>["https://sendgrid.com/docs/Classroom/Basics/API/cors.html"]}
 => nil

My friend sent the same code from his computer and its working.. no idea what to do. Im working on Cloud9, maybe thats the problem.. i dont have to much experience in coding so id really appreciate your help guys :)

My production.rb

Rails.application.configure do

ActionMailer::Base.smtp_settings = {
    :address        => 'smtp.sendgrid.net',
    :port           => '587',
    :authentication => :plain,
    :user_name      => ENV['SENDGRID_USERNAME'],
    :password       => ENV['SENDGRID_PASSWORD'],
    :domain         => 'heroku.com',
    :enable_starttls_auto => true
    }
# Code is not reloaded between requests.

config.cache_classes = true
config.eager_load = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { :host => 
 'myapp.herokuapp.com', :protocol => 'https'}

# Full error reports are disabled and caching is turned on.

config.consider_all_requests_local       = false
config.action_controller.perform_caching = true

# Attempt to read encrypted secrets from `config/secrets.yml.enc`.

# Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or

# `config/secrets.yml.key`.

 config.read_encrypted_secrets = true

# Disable serving static files from the `/public` folder by default since

# Apache or NGINX already handles this.

config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

# Compress JavaScripts and CSS.

config.assets.js_compressor = :uglifier

# config.assets.css_compressor = :sass

# Do not fallback to assets pipeline if a precompiled asset is missed.

config.assets.compile = false

My development.rb

Rails.application.configure do

config.cache_classes = false

# Do not eager load code on boot.

config.eager_load = false
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { :host => 
'https://myapp.c9users.io'}

# Show full error reports.

config.consider_all_requests_local = true

# Enable/disable caching. By default caching is disabled.

if Rails.root.join('tmp/caching-dev.txt').exist?
    config.action_controller.perform_caching = true

    config.cache_store = :memory_store
    config.public_file_server.headers = {
      'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}"
    }
else
    config.action_controller.perform_caching = false

    config.cache_store = :null_store
end

Environment.rb

require_relative 'application'

Rails.application.initialize!


ActionMailer::Base.smtp_settings = {
    :address        => 'smtp.sendgrid.net',
    :port           => '587',
    :authentication => :plain,
    :user_name      => ENV['SENDGRID_USERNAME'],
    :password       => ENV['SENDGRID_PASSWORD'],
    :domain         => 'heroku.com',
    :enable_starttls_auto => true
}
kaspar9
  • 31
  • 2
  • You must check the logs to see the specific error, and you should post the log here. – Pablo Apr 02 '18 at 16:45
  • yeah, couldnt add logs because of some reaseon.. :/ anyway ive tried to sens mail with helper in development: – kaspar9 Apr 04 '18 at 17:37
  • The code you tried to use directly is quite different from the one suggested by SendGrid. Maybe you could try this: https://sendgrid.com/docs/Integrate/Code_Examples/v2_Mail/ruby.html – Pablo Apr 04 '18 at 20:08
  • i will try it. thank u! – kaspar9 Apr 05 '18 at 21:38
  • https://community.c9.io/t/how-can-i-send-email-from-my-app/1262 Cloud9 is blocking ports, thats why its not working i guess:)) – kaspar9 Apr 05 '18 at 22:43
  • `ActionMailer::Base.smtp_settings` code is not needed in your `environment.rb` and in your `production.rb' when your are using SendGrid API. – zmd94 Apr 10 '20 at 07:09

1 Answers1

5

The SendGrid API is pretty fragile, and even more so in Rails. You're probably getting that error because you're using Mail instead of SendGrid::Mail. The sample code provided by SendGrid has this flaw, presumably because they tested it in a Ruby script instead of a Rails environment. Mail is already an existing class in Rails, and Rails does this weird thing where everything is automatically imported everywhere, unlike normal Ruby code.

Change the relevant lines to something like this, instead:

mail = SendGrid::Mail.new(from, subject, to, Content.new(type: 'text/plain', value: 'hi this is a test email'))
mail.add_content Content.new(type: 'text/html', value: '<h1>test email</h1><p>hi</p>')

Also note that if you want to send both a plain-text and an HTML body, you have to do it that EXACT order.

If you don't pass any content into the new method, and just call add_content twice, you'll get another one of those nonsense Invalid type. Expected: object, given: string errors, because the constructor will add nil to the list of contents.

If you pass the HTML content into the constructor and call add_content for the plain-text content, you'll get a different error saying that the plain-text content HAS to be added first.

A generally useful thing to do when you're getting these errors is to print out mail.to_json. That will give you a little more insight into what your code is sending to SendGrid.

Andrew Koster
  • 1,550
  • 1
  • 21
  • 31