Best practice for not delivering certain mails in development - ruby-on-rails

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)

Related

How do you disable Action Mailer in Rails 4 when running tests?

I'm trying to disable Action Mailer from actually sending out emails in Rails 4 and I am wondering how I might go about doing this. In my config/environments/test.rb file I have these two lines:
config.action_mailer.delivery_method = :test
config.action_mailer.perform_deliveries = false
and I also tried to place this line in the environment.rb file:
ActionMailer::Base.delivery_method = :test
as was suggested by other posts but these methods don't seem to work.
Can anyone provide me with any suggestions or advice on how to disable Action Mailer when I am running tests?
Thanks

In Rails 3, can we restrict which domains receive emails from our staging server?

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.

Rails, test mailer url

My application sends E-mails containing absolute urls.
I set host in config/environment/development.rb
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
Now I want to test if Email contains valid url. Using regular expression I take out full url from E-mail and want to visit this address using Capybara function.
mail = ActionMailer::Base.deliveries.last
address = mail.body.to_s[%r{http.+/edit}]
visit address;
But I don't know what host should be set in config/environment/test.rb
When I set localhost:3000 it tries to connect to my local server started by rails server command.
Do you have any ideas to solve this problem?
What worked for me:
Capybara.server_port = 3005
(see https://github.com/vangberg/capybara/commit/5784f03d6aa87e63e759abda794a43738e4f320f)
and
config.action_mailer.default_url_options = { :host => 'localhost:3005' }
To enable this to work when hardcoding Capybara ports is not an option (eg. parallel specs), put this in your spec_helper.rb
YourApp::Application.config.action_mailer.default_url_options[:host] = "localhost:#{Capybara.server_port}"
Instead of visiting the URL why not just validate it against a RegEx, make sure that it is valid, encoded correctly, points to the right controller.
You probably don't want to actually interact with the server, and if you do not the production server so localhost:3000 is a goo option
Hey here is scary code snippet that maybe could help you. I use email_spec to simplify working with email in specs and cucumber scenarios and it already has some helpers to simplify your task. In my application I have a little more complexer situation so I was forced to write my own parser. Here is the code. Enjoy:)

Controlling the logging and sending of emails in different environments

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

What is the "best practices" approach to setting up custom global email defaults in Rails?

I'm starting a new Rails 3 app from scratch.
And as I was going through basic setup ( configuring gems, sessions, etc) I ran into something that has been nagging me for a while.
Our current system ( a mixture of Ruby scripts & Rails 2 app) send various email / fax notifications to clients. There are certain things that are common in 80% of cases - cc - certain email accounts on our end and email signature.
Previously I just defined GLOBALS in the environment.rb such as
SYSTEM_EMAIL_SIGNATURE
or
SYSTEM_EMAIL_NOTIFY
and used them later in mailers or if it was a stand-alone script I had a setup.rb file - that had a bunch of common settings - including a has with custom email settings like this.
Since I'm rebuilding this app from scratch and consolidating all scripts into one ruby app - I was trying to think of a better way to do this.
Right now I'm setting up an email.rb Initializer that has action_mailer settings, that I extended by adding a few more items:
########## Setup Global Email Defaults ##############
Site::Application.configure do
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => 'mail.example.com',
:port => 25,
:domain => 'example.com',
# These are custom to OUR setup - used later in the code
:default_from => 'it.systems#example.com',
:default_notify => ["it.manager#example.com"],
:default_signature => "
---------------------------
This is an automatic email.
If you have any questions please contact customer service
at 1 (800) 888-0000 or go to http://www.example.com.
Thank you for your business!"
}
end
So is this a good approach? Or is there a better way then these two approaches?
I think you're on the right track for default_from and default_notify.
I wouldn't use SMTP settings for that; those aren't SMTP settings, they're just general mailer settings.
I'd go with something like this in an initializer:
MAILER_SETTINGS = YAML::load(open(File.join(Rails.root, "config", "mailer.yml")).read)[Rails.env]
With a yaml file that looks like this:
development: &development
default_from: foo#bar.com
default_notify: ["foo#bar.com"]
production:
<<: *development
default_from: production#bar.com
That lets you set defaults, then cascade them down and override per-environment as desired.
However, for the signature, I'd just move that into a partial, which you then include in your mail templates. They're views like any other and can have layouts, partials, and all of that.

Resources