how to place SMTP configuration on a separate file? - ruby-on-rails

I'm configuring my app to send emails through gmail smtp, so I'm writing the action_mailer setup in the production.rb file.
Though I don't want to have my gmail credentials written in the production.rb file, which is git versioned.
this is what I have made so far:
in production rb:
require "SmtpData"
config.action_mailer.default_url_options = {:host => 'my server's ip'}
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
enable_starttls_auto: "true",
address: SmtpData::ADDRESS,
port: SmtpData::PORT,
domain: "pjforex.com",
authentication: :plain,
:user_name => SmtpData::USER,
:password => SmtpData::PASS
}
then I created config/initializers/smtp_data.rb containing:
class SmtpData
USER = 'user#gmail.com'
PASS = 'password'
ADDRESS = "smtp.gmail.com"
PORT = "587"
end
But when my capistrano tries to precompile the assets, I get :
rake aborted!
uninitialized constant SmtpData
any clue on how to solve this. or better approach to this issue?
thanks,

You need to store your configuration in a file excluded from Git but shared between deployments. Assuming you are using Capistrano 3, it would be something like this:
1) On your server create a file shared/config/smtp.yml (using YAML is not something crucial, but it's just cleaner for configs) in Capistrano root folder with the following content:
user: user#gmail.com
pass: your_password
address: smtp.gmail.com
port: 587
2) Add this file to your linked_files in config/deploy.rb (ideally, config/database.yml should be stored this way too):
set :linked_files, %w{config/database.yml config/smtp.yml}
3) Read SMTP config in production.rb from config/smtp.yml.
4) You can also have config/smtp.yml locally for your development environment, but don't forget to add it to your .gitignore then.

I believe that production.rb gets loaded before smtp_data.rb, which is why production.rb isn't able to access the class you have defined.
One solution we use, to keep sensitive credentials out of our git versions, is to create (as in your example) production.rb.template and add this to your git repository. This file is pretty much a copy of what you currently have for production.rb, except that you would have placeholders for where credentials should go. For example,
:username => USERNAME GOES HERE
Then, we remove production.rb from the repository (and, optionally, set it to be ignored by git). When you check out your local copy of the repository, you copy production.rb.template as production.rb, and you fill in the credential information. This will only exist in your local deployment and would not be pushed to git.

Related

devise not sending recover password email

the mail configuration is through smtp.
everything is working ok with localhost in dev mode, devise sends recover password email using smtp conf in development.rb
manual mail sending with action mail is also ok
when in production mode,
only the host is modified to match the host in production machine
the smtp conf is unchanged, and manually sending mail is ok in a rails console
BUT devise does not send recover password mail
how to debug that ?
is Devise really taking on the global mail conf in production.rb ?
there is no Devise::Mailer override.
and this is uncommented in initializer
please share the github page of your project, so we can have a look. Then also share the log of your production server. you can recover it with heroku logs. I did configure this for my apps, eventually it broke down. It is a little bit tricky. I did follow some guide. If you did the same quote the guide you followed. I followed this guide, I remember that I had to allow in my gmail account setting the usage of gmail account from my app. Then there is some settings that you need to do in production.rb, I am quoting the guide, go to that link to see the full guide and check also other guides online:
Setting Up Production Environment
Now you will need to edit the file “config/environments/production.rb”. We will be adding very similar things to this file. First you can add:
config.action_mailer.default_url_options = { :host => 'yoursite.herokuapp.com' }
NOTE: You may also need to add this line. When I was setting up the mailer, I did not find this line in any other tutorials. I had the development mailer working, however I could not get heroku to work. I received this error in the heroku logs:
ActionView::Template::Error: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true
I found the answer here: ActionView::Template::Error: Missing host to link to on stackoverflow. If you come across this, then add:
Rails.application.routes.default_url_options[:host] = 'yoursite.herokuapp.com'
to your production.rb file.
Next you will have to add in these lines. Once again make sure that you leave the variables as they are.
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = false
config.action_mailer.default :charset => "utf-8"
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
domain: ENV["GMAIL_DOMAIN"],
authentication: "plain",
enable_starttls_auto: true,
user_name: ENV["GMAIL_USERNAME"],
password: ENV["GMAIL_PASSWORD"]
}
read the comments from this post and all the other relevant guides to configure this, you may need to use some smtp api to send the email....

Net::SMTPAuthenticationError (535-5.7.8 Username and Password not accepted.) Openshift production only

I'm trying to send an email through gmail/actionmailer, it works perfectly on my local development box, but when I try and run the same code on production server it gives me an Net::SMTPAuthenticationError (535-5.7.8 Username and Password not accepted.. I think this is because gmail is rejecting my login credentials from an unknown server.But I'm not sure! How do I fix it?
Background:
I am using the figaro gem, and I am setting my environment variables on the openshift server with: rhc set-env. I've checked that the environment variables are set on the server.
The questions here, here, and here are all good, but have not done anything to solve my problem. My problem is a bit different because it only shows up on my server, everything works fine on my local box.
Development:
In development mode, I have the figaro gem installed, and I have my configuration file stored in application.yml which is not checked into git.
Here are it's contents:
## config/application.yml
# Add configuration values here, as shown below.
gmail_username: 'PLACE_HOLDER_EMAIL#gmail.com'
gmail_password: 'PLACE_HOLDER_PASSWORD'
In my controller:
## PLACEHOLDER_controller.rb
def create
#placeholder = Placeholder.new(placeholder_params)
respond_to do |format|
if #placeholder.save
puts "SENDING..."
puts "Sending to: #{ENV['gmail_username']}..."
PLACEHOLDERMailer.placeholder_email(some, params).deliver
puts "SENT!"
end
end
Production:
## /config/environments/production.rb
# SMTP
config.action_mailer.delivery_method = :smtp
# SMTP settings for gmail
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:user_name => "#{ENV['gmail_username']}",
:password => "#{ENV['gmail_password']}",
:authentication => "plain",
:enable_starttls_auto => true
}
Production:
I push the code to my OpenShift repo with git, the server restarts, ostensibly everything is fine. Except that when I create a new placeholder, I get a 500 back from the server.
Here is the log output:
>> rhc tail -a MY_APP
SENDING...
Sending to: "PLACE_HOLDER_EMAIL#gmail.com"... ## This is the correct email! It's clearly pulling the proper values from ENV.
INFO -- : Rendered placeholder_mailer/placeholder_email.text.erb (0.1ms)
INFO -- :
Sent mail to 9739069711#txt.att.net (132.3ms)
INFO -- : Completed 500 Internal Server Error in 224ms
FATAL -- :
Net::SMTPAuthenticationError (535-5.7.8 Username and Password not accepted. Learn more at
):
app/controllers/placeholders_controller.rb:35:in `block in create'
app/controllers/placeholders_controller.rb:29:in `create'
Which says that the username and password were not accepted. Now, I know that I have the correct username and password. I'm fairly certain that's not the issue. I suspect that (as mentioned in the linked questions) smtp.gmail.com is rejecting my login from an unknown server.
Before anyone suggests it, I have already:
Disabled Two Factor Authentication
Tried creating an application specific password and using that instead. (Didn't work, I've now switched back to the regular account password)
Enabled access to less secure applications.
TL;DR
I'm trying to send an email from the server. When I run it on the server it gives me: Net::SMTPAuthenticationError (535-5.7.8 Username and Password not accepted.. I think this is because gmail is rejecting my login credentials from an unknown server. How do I fix it?
It turns out that gmail blocks you temporarily if you try to access it programatically more than once every ten minutes. I suppose I must have did this while I was testing the functionality.

How to generate URL with host in Rails development environment?

I am working on an application that has set its default host to localhost:
config.action_controller.default_url_options = { host: "localhost" }
config.action_mailer.default_url_options = { host: "localhost" }
This works fine if you're serving your app on a specific port (like http://localhost:3000). I am using Pow so that I can access the app from a URL like http://myapp.dev.
How can I change this setting so that it will work with my domain as well as the other developers using localhost? I need to generate full URLs since they will be used in emails. Is it possible to pass some sort of config value to Pow?
This is the best way I found:
1- Create a config/smtp_settings.example.yml file:
development:
:method: :letter_opener
:url_options:
:host: localhost
:port: 3000
production: &production
:method: :smtp
:url_options:
:host: www.the_site.com
:smtp_settings:
address: smtp.gateway.com
port: 465
user_name: someone#somewhere.com
# etc ...
staging:
<<: *production
test:
:method: :test
:url_options:
:host: test.host
Notes:
This uses letter_opener as development mailer, change to your own method
There is a staging environment defined as an exact copy of the production environment, remove if you don't use staging
2- Remove config.action_mailer.delivery_method and config.action_mailer.default_url_options and config.action_mailer.smtp_settings from all files under config/environments/ folder
3- Add in the file config/application.rb the following:
config.action_mailer.delivery_method = config_for(:smtp_settings)[:method]
config.action_mailer.default_url_options = config_for(:smtp_settings)[:url_options]
config.action_mailer.smtp_settings = config_for(:smtp_settings)[:smtp_settings] if config_for(:smtp_settings)[:method] == :smtp
Notes: config_for has been introduced in the latest version of Rails (4.2.0 as per writing). If you use an older version of rails you must manually load the yml files
And the trick on top of all of that to answer your question:
Push to your repository the file config/smtp_settings.example.yml and ignore the file config/smtp_settings.yml.
Each developper of your team would have to create their own config/smtp_settings.yml by copying the file smtp_settings.example.yml and changing the host to match their machine's IP address, so the mail send by each developer leads to their own machine.
You off course requires you to start the local development server binded to 0.0.0.0 so it's accessible from other hosts (considering your security environment off course)
You could use an environment variable to configure a default host. See Luc Boissaye's answer on how to set this up with dotenv. If you don't add the .env to your repo, each developer can create his own .env and configure his (or her) own preferences.
But you can also use existing environment variables to configure the default_url_options. For example Pow.cx sets the POW_DOMAINS variable:
config.action_mailer.default_url_options = {
ENV['POW_DOMAINS'].present? ? 'my-app.dev' : 'localhost'
}
As far as I know you only need to set the config.action_controller.default_url_options if you want to force it to some default. When you use the rails _path helpers in your views, this will generate a relative URL (/path). If you use the _url helpers, this will generate an absolute URL (http://your.host/path), but both the protocol (http) and host (your.host) are request based.
In development, I like to use dotenv gem(https://github.com/bkeepers/dotenv).
I put in .env :
DOMAIN=myapp.dev
And I put inside config/route.rb:
MyApplication::Application.routes.draw do
default_url_options host: ENV['DOMAIN']
In production I define on heroku my domain with this command :
h config:set DOMAIN=myapp.herokuapp.com
or with a custom domain :
h config:set DOMAIN=superdomain.com
This will check if Application root directory is symlinked in .pow of current user and set the host accordingly.
if File.exists?(Dir.home+"/.pow/#{Rails.root.basename}")
config.action_mailer.default_url_options = { host: "#{Rails.root.basename}.dev" }
else
config.action_mailer.default_url_options = { host: "localhost" }
end
Described on Action Mailer Basics:
Unlike controllers, the mailer instance doesn't have any context about the incoming request so you'll need to provide the :host parameter yourself.
As the :host usually is consistent across the application you can configure it globally in config/application.rb:
config.action_mailer.default_url_options = { host: 'example.com' }
Because of this behavior you cannot use any of the *_path helpers inside of an email. Instead you will need to use the associated *_url helper. For example instead of using
<%= link_to 'welcome', welcome_path %>
You will need to use
<%= link_to 'welcome', welcome_url %>
The use of Pow makes things a little trickier but thankfully it integrates with XIP.io so you can access myapp.dev from machines on the local network. Just follow the instructions here: Accessing Virtual Hosts from Other Computers.
The question doesn't mention this, but it might be useful information - If you'd like to actually send mail in your dev (or perhaps test/staging) environment, Instead of seeing mail just in the rails console (with something like powder applog), I'd recommend just hooking it up to a gmail.
You need to override default_url_options in your application controller (at least in rails 3)
http://edgeguides.rubyonrails.org/action_controller_overview.html#default_url_options
class ApplicationController < ActionController::Base
def default_url_options
if Rails.env.production?
{:host => "myproduction.com"}
else
{}
end
end
end

ActionMailer not sending mail in development Rails 4

Why is this mailer not sending any mail? (Or any ideas for debugging?)
In my_app/config/environments/development.rb I have this code:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.gmail.com',
port: 587,
domain: 'my_app.com',
user_name: ENV['GMAIL_USERNAME'],
password: ENV['GMAIL_PASSWORD'],
authentication: 'plain',
enable_starttls_auto: true }
Then on my local computer in ~/.bash_profile I have this code:
export GMAIL_USERNAME='blah#my_app.com'
export GMAIL_PASSWORD='***'
When I run $ env in my terminal, I see that both environment variables are correctly set.
I have also restarted my rails server.
You should add
config.action_mailer.perform_deliveries = true
as by default this is on false, preventing mails to be sent from your development environment...
For anyone not using smtp, switching the delivery method to sendmail helped me in addition to explicitly setting deliveries to be performed:
config.action_mailer.delivery_method = :sendmail
If you're having issues sending email from console, you have to call the deliver method on your mail.
MyMailer.create_email.deliver
All of these answers are great, but there is another place where you can get burned, especially in the context of debugging.
In development.rb make sure you set config.action_mailer.raise_delivery_errors = true
If your .deliver method seems to be working without issue, but you never actually receive the email across the wire, your delivery method may be throwing an exception and rails is swallowing the error. This is very true if you simply have something as simple as a misconfigured credentials, or an aws access denied API error. Save ripping your hair out and make sure you have raise_delivery_errors turned on. It wants to tell you something but can't.
So I've figured it out. Having the line ActionMailer::Base.delivery_method = :smtp in config/environment.rb overrides ActionMailer::Base.delivery_method = :test in config/environments/test.rb.
So, delete that line, ActionMailer::Base.delivery_method = :smtp from config/environment.rb and place it in config/environments/production.rb. That allows you to place ActionMailer::Base.delivery_method = :test in config/environments/test.rb and the version you want in config/environments/development.rb. I made development.rb :test as I populated my database using Faker and changed it to :smtp so I was sure that real emails were sent as an additional check.
Note: You must restart your server for these changes to take effect.
Another note: Heroku's current SendGrid Instructions (https://devcenter.heroku.com/articles/sendgrid) put the SendGrid Heroku configuration code in a new config/initializers/mail.rb file which will likely require removing its last line and placing the desired version in each config/environments/[production.rb, development.rb, test.rb]

Thin server not loading environment variables with Capistrano

I'm deploying my rails app with capistrano and using the thin server. I have 2 env vars for my mailer username and password defined in ~/.bash_profile with export SMTP_USERNAME=....
When I ssh to the server and try to send emails from the rails console it works fine but it looks like they are not loaded by thin when I run cap deploy or any other command.
What's the correct way to define them? I've seen some posts where they suggest to define them directly in the config/environments/production.rb or in some other file related to the code itself. I was trying to avoid that for security reasons.
UPDATE: I tried to use a yml file to store this but I ran into this problem:
I created a new file email_config.rb in config/initializers. Its content is:
EMAIL_CONFIG = YAML.load_file("#{RAILS_ROOT}/config/email.yml")[RAILS_ENV]
In config/email.yml I have:
production:
username: username
password: password
In my config/environments/production.rb I have:
config.action_mailer.delivery_method = :smtp
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default :charset => "utf-8"
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
authentication: :plain,
enable_starttls_auto: true,
user_name: EMAIL_CONFIG[:username],
password: EMAIL_CONFIG[:password]
}
Now the problem is that initializers are loaded after environments.rb and if I put the definition of the EMAIL_CONFIG variable just before my email configuration, then the RAILS_ROOT variable is not define.
Like you're saying, not a god idea to save a password directly in the production.rb. A better option would be to reference them from shell variables (closer to your current setup) or from a yaml file (what I do personally). You can find more information in this post

Resources