In a Rails application I set up a new staging environment with the following parameters in its environments/ file:
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
However, when the system generates an email, it gets printed to the staging.log file instead of being sent. My SMTP settings work fine in other environments. What configuration am I missing to get the emails to actually send?
Edit: Yes, the staging box is set up with valid configuration for an SMTP server it has access to. It seems like the problem isn't with the SMTP settings (if it was, wouldn't I get errors in the logs?), but with the Rails configuration. The application is still redirecting emails to the log file (saying "Sent mail: ...") as opposed to actually going through SMTP.
Edit #2: It looks like the emails actually have been sending correctly, they just happen to print to the log as well. I'm trying to use the sanitize_email gem to redirect the mail to another address, and that doesn't seem to be working, which is why I thought the emails weren't going out. So I think that solves my problem, although I'm still curious what in ActionMailer's settings controls whether emails are sent, logged to the log file, or both.
Edit #3: The problem with sanitize_email boiled down to me needing to add the new staging environment to ActionMailer::Base.local_environments. I'll keep this question open to see if anyone can answer my last question (what determines whether ActionMailer's emails get sent out, logged to the log file, or both?)
Regarding your third edit, the logging is a function of which log level you have set for the app itself, not any particular setting in ActionMailer.
In Rails 2.3, ActionMailer::Base simply send the email to whatever logger has been configured, if any. The recipient is sent to the info log and the body of the email is sent to the debug log. (Comments are mine. The rest is straight out of the source code.)
def deliver!(mail = #mail)
raise "no mail object available for delivery!" unless mail
#
# Logging happens first (or not)
#
unless logger.nil?
logger.info "Sent mail to #{Array(recipients).join(', ')}"
logger.debug "\n#{mail.encoded}"
end
#
# And then we decide if an email should really get sent
#
begin
__send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries
rescue Exception => e # Net::SMTP errors or sendmail pipe errors
raise e if raise_delivery_errors
end
return mail
end
Your environment.rb or staging.rb file should have a line that controls the log level. Something like the following:
config.log_level = :debug
This is all completely separate from the mailer configuration that you already found, which controls whether the email is sent or not.
config.action_mailer.perform_deliveries = true
Related
We have a center/course platform. Every time a new student is interested in a course we send an email to de center to notify them about it.
However, we don't want this to happen in development, as centers would receive 'false' notifications.
Firs thing comes to my mind is introducing unless Rails.env == 'production' wherever we don't want to send an email. But it feels a little bit weird.
What would it be the best solution/pattern to accomplish this?
Note that we don't want to stop sending mails to everyone, but just some of them.
Thanks in advance.
In your config/environments/development.rb (and test.rb) you can do:
Rails.application.configure do
#.......other config here
config.action_mailer.delivery_method = :test
end
This does not send the email, but you can see it in the log file/terminal output
I think what you're looking for is this:
Add this to your config/environments/development.rb
config.action_mailer.perform_deliveries = false
or
config.action_mailer.delivery_method = :test
to log the deliveries
(If you're using ActionMailer)
I have a rails app where I want to send people an email when they sign up. The email has a link to their photos portal so they can get started adding photos, etc..
class MyMailer < ActionMailer::Base
def welcome_email
# ...
link = photos_url # => www.myapp.com/photos
# ...
end
end
The problem is that when I push my code to Heroku and run it live, that link doesn't generate as expected.
The photos_url returns the URL relative to the localhost and ends up generating myapp.herokuapp.com/photos, which is incorrect.
What's even stranger is that if I pause the code at that point with binding.pry and try to see what photos_url is returning, it correctly returns www.myapp.com/photos as expected.
Any thoughts on how to resolve this? I'd hate to have to construct the URL myself from scratch, because that means I have to do it for every environment (localhost, staging, production, etc...)
Thanks!
ActionMailer isn't tied to the request/response cycle, thus it doesn't know what's the host the app is currently running on. Actually, emails are typically sent by some background worker processes which know nothing about the current request URL.
So to make it work you need to set the ActionMailer default_url_options.host option.
Add this into you config/environments/production.rb:
config.action_mailer.default_url_options = { host: 'www.yourapp.com' }
We want to test email functionality on our staging server, but we don't want to accidentally email customers.
So, I'd like emails sent to "anything#corporation.com" to work, but emails sent to "anything#customer.com" to be suppressed.
I could just go into all of my controllers and put in code that only fires the "deliver" method if the email contains our domain or the environment is prod. But, that seems kinda kludgey. I'd like to do it app wide.
Applications that use the Mail gem (including rails >= 3.0 projects) can use the safety_mailer gem. Specify a domain (or set of domains, or magic word in email address) email is allowed to go to, and email to all other domains is silently dropped.
https://github.com/cluesque/safety_mailer
Add the gem to your Gemfile, specifying groups (probably not production) to include it in.
gem "safety_mailer", :group => :development
Don't forget to bundle install to install
In your environment file config/environments/development.rb configure it, and some regular expressions.
config.action_mailer.delivery_method = :safety_mailer
SafetyMailer::Config.allowed_matchers = [ /mydomain.com/, /mytestacct#gmail.com/, /super_secret_test/ ]
... and now, email to anyone#mydomain.com, mytestacct#gmail.com, bob+super_secret_test#yahoo.com all get sent
and email to other recipients (like the real users in the production database you copied to a test server) is suppressed.
Here is an example with an interceptor:
Create an initializer /config/initializers/mailer_config.rb :
require 'staging_mail_interceptor'
ActionMailer::Base.register_interceptor(StagingMailInterceptor) if [test here if on staging server]
The file /lib/staging_mail_interceptor.rb contains the interceptor, where you can modify the message before it is sent. In my case I tag the subject and redirect all mails to my personal email. You can put here the code to filter the domains:
class StagingMailInterceptor
def self.delivering_email(message)
message.subject = "TEST #{message.to} - #{message.subject}"
message.to = 'test#corporation.com'
end
end
Modify the delivery_method option for your staging environment - this is a lot less messy than putting in code in your controllers, and then having to rip it back out, because you simply modify a setting, and change it back.
delivery_method - Defines a delivery method. Possible values are :smtp
(default), :sendmail, :test, and :file.
In this case you probably want to use :test, or :file. :file will dump the contents of the email to a file so you can be sure that the email is being rendered the way you expect it to be, with the proper names inserted, etc., without actually sending an email out on the interwebs.
Typically, you don't need to make sure that ActionMailer will actually send email - it does, and it's a well tested module all its own.
An alternative solution, if you really need a full-stack test, is to modify the recipient list for staging only. If you're sending the email to a distribution list, then point it to a different distribution list for staging. If you're sending to a list of emails from the database, then temporarily remove (or mark as inactive) the email addresses you don't want to send to.
I'm trying to find a little bug and need the logger inside one of my models for it. Whenever I use
logger.debug "something"
inside a model, the message is put in the log but I get a 500 Server Error page. Everything is normal without the logger.debug line.
I set
config.log_level = :debug
inside the environments/production.rb file and set the correct file permissions for the log but can't seem to find the problem.
Inside the model the logger object is not available by default. Use
Rails.logger.debug "something"
instead...
So for static email in the system, I have a staging environment config setup which works well.
With dynamic emails, I have this code in my mailer.rb file.
if RAILS_ENV == 'staging'
recipients STAGING_TEST_EMAIL
else
recipients request[:email]
end
This works, I just wanted to know if there was a tidier or better way to do this or if this is OK in terms of best practice.
One option, is to modify the staging servers mailing gem..
IE...
def email.press_send
recipients STAGING_TEST_EMAIL
end
My personal favorite...
is to talk to the sys admin and arrange for email sent from the staging, test, box directly into a file, so then you can view it.
ie, all email sent out is sent to this user "test_email", who has this .forward "| cat >> /tmp/new_mail.txt"