Rails 5 app cant send sendgrid emails (Cloud 9 and Heroku) - ruby-on-rails

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
}

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.

Related

Sendgrid not sending email?

I am trying to implement sendgrid into my backend api rails system so that when a user signs up I can send them a welcome email. After making a post request and handling user creation, I get this verification:
UserMailer#send_sign_up_email: processed outbound mail in 43.5ms
Sent mail to *******#gmail.com (185.8ms)
Date: Wed, 28 Feb 2018 16:54:05 -0800
From: *******#gmail.com
To: *******#gmail.com
Message-ID: <5a974f2d39c92_c5b2abcd76769fc423e0#albert-VirtualBox.mail>
Subject: Welcome to BottlesTonight albert jin!
Mime-Version: 1.0
Content-Type: text/html;
charset=UTF-8
Content-Transfer-Encoding: quoted-printable
My code looks exactly like in this link https://sendgrid.com/docs/Integrate/Frameworks/rubyonrails.html.
This looks all fine and well, but the email is just not sending (I put stars here for the email but I actually put in my email, and I used another one of emails as the default for sending). There is no email in my outbox or inbox.
However, now that I think about it, I never "logged in" with my email or entered the password, so the application shouldn't have access to send emails with my email. I also never did anything with the api key that I made on my sendgrid account. Furthermore, for the environment.rb file, I wasn't sure what to put in domain, so I put gmail.com. These all seem kinda sketchy to me, I think the tutorial doesn't contain everything. Does anyone know how to configure this? I've been stuck on it for a while.
Edit:
I tried doing it on production and it is not working. Here is more info:
My production.rb looks like this:
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = { :host => ENV['DEFAULT_HOST'] }
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
}
I have a heroku sendgrid add on. I have set the heroku config vars. In my registrations controller I merely added the line:
UserMailer.send_sign_up_email(#current_user).deliver
My mailer class looks like:
def send_sign_up_email(user)
#user = user
mail(to: #user.email, subject: "Welcome! #{#user.first_name}")
end
However, when I sign up on my website, the user gets added to the database but the email is not sending. Does anyone know why, or how I can debug?
I would suggest to remove all config for ActionMailer from your environment files (i.e. files under /config/environments), except following ones
# Don't care if the mailer can't send.
config.action_mailer.perform_caching = false
# Reference: http://stackoverflow.com/a/20770131/936494
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
Then create an initializer /config/initializers/mail_config.rb and add following code to it:
TEST_ENVS = %w(test)
FILESYSTEM_ENVS = TEST_ENVS + %w(development)
# =========== DELIVERY METHOD SETTING
delivery_method = case Rails.env.to_sym
when :production, :staging, :experimental
:sendmail
when :test
:test
else
:smtp
end
ActionMailer::Base.delivery_method = delivery_method
# =========== SMTP SETTINGS
ENVS_TO_USE_GMAIL_CONFIG = %w(development test)
gmail_config = {
address: 'smtp.gmail.com',
port: 587,
domain: 'gmail.com',
user_name: ENV['MAIL_USER_NAME'],
password: ENV['MAIL_PASSWORD'],
authentication: :plain,
enable_starttls_auto: true
}
if :smtp == delivery_method
use_gmail_config = ENVS_TO_USE_GMAIL_CONFIG.include?(Rails.env)
smtp_settings = ( use_gmail_config ? gmail_config : {} )
ActionMailer::Base.smtp_settings = smtp_settings
end
# =========== DEFAULT URL OPTIONS
default_url_options_settings = Settings.default_url_options
host = default_url_options_settings.host
port = default_url_options_settings.port
protocol = default_url_options_settings.protocol
default_url_options = {}
default_url_options[:host] = host if host.present?
default_url_options[:port] = port if port.present?
default_url_options[:protocol] = protocol if protocol.present?
ActionMailer::Base.default_url_options = default_url_options
The Settings object is available as part of using config gem. If you do not want to use that gem for configuring env-specific values then you can just hard-code them in the initializer and try it.
My /config/settings.yml looks like
default_url_options:
host: ''
port: ''
protocol: ''
and my /config/settings/development.yml looks like
default_url_options:
host: 'localhost'
port: '3000'
Having a centralized mailer config helps in diagnosing mailer settings related issues in quick manner.
First try it for Gmail account and if it works you can be sure that sending email works. Just make sure in your Gmail account Less Secure Apps setting is enabled.

Ruby on rails action mailer sending mails from previous setting

Hi i have an app in which i am using action mailer to send the mail ,
i am drowned in this really weird issue
the issue is i set up the mail setting in the development and the production environment to send the mails from the gmail domain . that worked perfectly but then i decided to send emails from my domain
which i purchased from the go daddy
this is my code
development.rb
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
config.consider_all_requests_local = false
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
ActionMailer::Base.perform_deliveries = true
# SMTP settings for gmail
config.action_mailer.smtp_settings = {
:address => "smtpout.secureserver.net",
:port => 80,
:domain => "jobzgo.com",
:user_name => 'mydomainemailid',
:password => 'mydomainpasswrd',
:authentication => "plain",
:enable_starttls_auto => true
}
in controller
def create
#form = Form.create(form_params)
if #form.save
FormMailer.registration_mail(#form).deliver
redirect_to forms_path
end
end
i dont know how but i am still receiving the mails from gmail domain and the old gmail id i provided as the sender
Can anyone please tell me why this is happening along with the solution
wud be really a great help stuck in this issue
You have set the default from: to your Gmail address in your app/mailers/application_mailer.rb.
BTW I would highly recommend you to move credentials out of the codebase into the environment variables.

Email for user confirmation not sending in production. Rails, Heroku, Devise, Gmail

I've looked all over Google and stackoverflow for an answer, but none of them work.
I'm trying to set up smtp emailing for user confirmation after signing up. It works fine in development. Even with MailCatcher on, it bypasses it somehow and sends to the right email from my assigned gmail.
Here's what's in development.rb:
config.action_mailer.default_url_options = { :host => 'localhost:3000'}
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {:address => "localhost", :port => 1025}
Here's what's in production.rb:
config.action_mailer.default_url_options = {:host => 'myapp.herokuapp.com', :protocol => 'http'} #I've also tried it without ":protocol => 'http'"
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:authentication => :plain, # I've also tried :login
:enable_starttls_auto => true, # Also tried tls => true
:user_name => 'myemail#gmail.com',
:password => 'mypassword'
} #I've also tried having the attribute :domain => 'myapp.herokuapp.com',
In config/initializers/devise.rb
config.mailer_sender = 'please-change-me-at-config-initializers-devise#example.com' #It still sends from myemail#gmail.com even with this line uncommented.
I don't know how to paste out my entire 7 pages (in word document) worth of heroku logs in code block, so I've pasted them in a google doc.
google doc of heroku logs (I believe I highlighted the part where it started to go wrong on page 1-2):
https://docs.google.com/document/d/1G-cCX7T1sPL5XtjyjHRaWmzfaBbWkuTR2edsDmDm1Pc/edit?usp=sharing
I'm not sure where it's finding the correct email to send from in development. I'm still a novice at this.
edit: I just found out that users that were registered before adding confirmation are not able to log in as well, so it might be a users problem with heroku. But everything still works fine in development.
Help is greatly appreciated, thanks!
You might miss this config.action_mailer.perform_deliveries = true
Please check if your gmail asked for captcha for sending the mail or not. and to debug the error please make config.action_mailer.raise_delivery_errors = true on your production.rb .Please check the similar question Net::SMTPAuthenticationError when sending email from Rails app (on staging environment)

Rails Mailer: change file when delivery_method :file

I want to have the file named Timestamp + normal_mail_name + ".eml"..
I looked into the rails source code, the mail-gem source code and the letter opener-gem.. Could you give me a hint how to (monkey-patch) the rails mailer to support that i can specify something like:
config.action_mailer.file_settings = { :location => Rails.root.join('tmp', 'mail'), :file_name => Time.now.to_i.to_s + "mail.eml" }
Thank you!
UPDATE:
It would be also nice to have this mails automatically opened with my local associated email programm with launchy, like the letter opener gem.. i would do it myself, but i dont understand the sourcecodes..
I think you have a lot of mailer stuff and you´ll want to debug the mail body, texts, etc.? Am I right?
If I am right, I would not send the mails with delivery_method :file, I just would create a real email (for example gmail) account and send the mails over a test account.
For example in your config/environments/development.rb:
email_settings = YAML::load(File.open("#{Rails.root.to_s}/config/mail.yml"))[Rails.env] rescue nil
if email_settings.nil?
config.action_mailer.raise_delivery_errors = false
config.action_mailer.perform_deliveries = false
config.action_mailer.delivery_method = :file
else
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_deliveries = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "#{email_settings["address"]}",
:port => email_settings["port"],
:authentication => "#{email_settings["authentication"]}",
:user_name => "#{email_settings["user_name"]}",
:password => "#{email_settings["password"]}",
:enable_starttls_auto => email_settings["enable_starttls_auto"]
}
end
And your mail.yml file:
development:
address: smtp.gmail.com
port: 587
authentication: login
user_name: test#your-domain.com
password: yourpassword
enable_starttls_auto: true
This is not really a direct answer for your question, but maybe this work around is a good choice for you. You could also configure your other environments the same way, dependent on your needs.
If you just want skip the transmission of the emails through a real mail server to view your emails locally, two good solutions I've used are:
https://github.com/ryanb/letter_opener
https://github.com/37signals/mail_view
A non-free, OSX-specific solution is to use http://mocksmtpapp.com/
If you want to have a copy of the raw email (headers and all), one way I would do it would be write an email interceptor and write the contents of the mail object to disk.
http://railscasts.com/episodes/206-action-mailer-in-rails-3
Something like this for lib/development_mail_interceptor:
class DevelopmentMailInterceptor
def self.delivering_email(message)
message.perform_deliveries = false
File.open("#{Time.now.to_i}-email.eml", "w") { |f| f.write(message.to_s) }
end
end
and in config/initializers/setup_mail.rb
Mail.register_interceptor(DevelopmentMailInterceptor) if Rails.env.development?

Actionmailer not delivering mail, with rails 3

I am trying to make an application, that sends an email when user registers.
i put in the smtp settings for gmail in the config/application.rb file and the mail function looks like
mail(:to => "me#me.com", :subject => "Mail!", :from => "another#me.com", :content_type => "text/html")
now when i see the logs, i see that it says mail has been sent, but i never receive any mail at all...
also, when i call the mail deliver function, Emails.signed(#user).deliver, the form page does not redirect, but it works if i comment out the email sending code that is either
Emails.signed(#user).deliver
or
mail(:to => "me#me.com", :subject => "Mail!", :from => "another#me.com", :content_type => "text/html")
Thanks :)
Edit: development.rb
App::Application.configure do
# Settings specified here will take precedence over those in config/environment.rb
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# since you don't have to restart the webserver when you make code changes.
config.cache_classes = false
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_view.debug_rjs = true
config.action_controller.perform_caching = false
# Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = true
config.action_mailer.perform_deliveries = true
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
end
Somewhat late, but nevertheless maybe this will save someone a few hours of head banging. This is probably only relevant to sending emails from gmail.
First, in order to help debugging the situation, set the following line in development.rb to true (assuming you're in development mode):
config.action_mailer.raise_delivery_errors = true
This will make ActionMailer not to silently ignore errors.
When I did that, I realized gmail is refusing my username and password.
I then went to my configuration file where I put all the Action Mailer config directives (for me it was in development.rb, there is probably a better place to put it), and noticed that :user_name was set to "admin" rather than "admin#thedomain.com". Changing it solved the problem. Here is my corrected part of development.rb:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => 'thedomain.com',
:user_name => 'admin#thedomain.com',
:password => '<password>',
:authentication => 'plain',
:enable_starttls_auto => true }
References:
http://forums.pragprog.com/forums/43/topics/541
http://edgeguides.rubyonrails.org/action_mailer_basics.html
Another thing not to forget: you have to restart the application after making changes in your environment config files. when using passenger this can quickly be missed :)
that's what solved my "problem" when ActionMailer didnt want to send emails without showing any errors..
The things written here did not help me.
I am using Rails 3.2.8 and I spent several hours trying to figure this out and it was very simple in the end. I forgot to call .deliver() on the Mail::Message object that is returned by mail(:to => #user.email, :subject => 'Welcome to the Site') method call.
Just leave everything like it is specified in official RoR tutorial.
That is, in your development/production environment files, make a section like:
# mailer
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.gmail.com',
port: 587,
domain: 'gmail.com',
user_name: '<username>#gmail.com',
password: '<password>',
authentication: 'plain',
enable_starttls_auto: true
}
And then you subclass ActionMailer::Base, for example like this:
class InfoMailer < ActionMailer::Base
default from: "<username>#gmail.com"
def welcome_user_and_send_password(user, password)
default_url_options = self.default_url_options()
#user = user
#password = password
#url = default_url_options[:host]
mail(:to => #user.email, :subject => 'Welcome to the Site').deliver()
end
end
After that, you can simply use this InfoMailer method from your code like a class method:
InfoMailer.welcome_user_and_send_password(user, password)
If you're using the test environment, be sure to comment out this line of code in environments/test.rb:
config.action_mailer.delivery_method = :test

Resources