Rails ActionMailer Mail Not Delivered From 3.2 App - ruby-on-rails

I upgraded my app from 3.0 to 3.1 to 3.2 (per the recommendations). All specs and scenarios pass and they test the email sent pretty deeply. What happens is that the email appears to be sent if I look at my maillog and the correct templates appear to be rendered, but no mail is actually delivered to the user.
This code worked perfectly in the 3.0 version of this app. I'm hoping someone can spot out what I'm missing. The first several files I've shown in the code below are configuration files. Again, this stuff worked fine in previous deploys. I'm baffled.
The "controller mixin" is a module that is mixed into any controller that wants to send mail. The controllers do almost exactly the same thing so all I have to change is the mailers and the views.
I'm stumped how to proceed even debugging this. I know I can specify more detailed smtp settings but this worked fine before and it is resilient once I prop this in DNS, not relying on a particular hostname.
Any thoughts are most appreciated!
production.rb
# other non-mailer stuff elided.
config.action_mailer.default_url_options = { :host => `hostname` }
ActionMailer::Base.default(:charset => 'utf-8')
ActionMailer::Base.perform_deliveries = true
config/initializers/setup_mail.rb
require 'development_mail_interceptor'
Mail.register_interceptor(DevelopmentMailInterceptor) if Rails.env.development?
lib/development_mail_interceptor.rb
class DevelopmentMailInterceptor
def self.delivering_email(message)
message.subject = "[#{message.to}] #{message.subject}"
message.to = "my.address#gmail.com"
end
end
Controller mixin (this is in a module that is mixed into controllers that do mail):
def send_detail_email
#detail_email = #mailer_klass.sent(#ar_obj, session)
end
def send_confirm_email
#confirm_email = #mailer_klass.confirm(#ar_obj, session)
end
def send_email
send_detail_email
# Field naming is inconsistent, so sniff out the contact type
contact_type = ''
contact_type = #ar_obj.contact if #ar_obj.respond_to?(:contact)
contact_type = #ar_obj.best_contact_method if #ar_obj.respond_to?(:best_contact_method)
contact_type = #ar_obj.contact_method if #ar_obj.respond_to?(:contact_method)
# If no contact type, then it's probably assumed a user object's email
contact_type = 'email' if #ar_obj.respond_to?(:user) &&
!#ar_obj.respond_to?(:contact) &&
!#ar_obj.respond_to?(:best_contact_method) &&
!#ar_obj.respond_to?(:contact_method)
send_confirm_email if contact_type == 'email'
end

Related

Override mail function in rails ActionMailer

I use this class for Action Mailer:
class UserMailer < ActionMailer::Base
default from: "something#example.com",
reply_to: 'whatever#example.com'
def mail_method
mail(to: 'email#example.com', subject: "SUBJECT")
end
end
So like this I got many classes and methods which send emails like this from smtp delivery method.
But now I want to perform_deliveries , i.e. send emails only on production environment not in development or test environment.
So for that I want to use my email only, which is why I need to override mail method.
Things I have tried.
-> Making a function to return email, where function name is get_right_email
class UserMailer < ActionMailer::Base
default from: "something#example.com",
reply_to: 'whatever#example.com'
def mail_method
mail(to: get_right_email('email#example.com'), subject: "SUBJECT")
end
end
And definition of get_right_email is as follows:
def get_right_email(email)
if(Rails.env=='production')
return email
else
return 'myPersonalEmail#example.com'
end
end
It would need some refactoring but it is still manageable. Will take a few hours and I can do, but is there a quicker way where I can just override mail function.
In your config > enviroments folder you should have a file for production, development and test. Here you can specify your settings for each one.
Settings in these folders overide those in config > application.rb
For example when testing I don't usually actually send the emails but I do want to be able to test the emails so I use
config.action_mailer.delivery_method = :test
This makes the emails accessible by calling ActionMailer::Base.deliveries
You can set the default from email address in these files as well using:
config.action_mailer.default_options = {
:from => "foo#bar.com"
}
Theres a gem called letter_opener managed by the fantastic Ryan Bates which instead of sending an email in development opens the email in a new tab. This makes testing out emails in development a breeze.
Letter Opener
UPDATE BELOW ------
Apologies, I didn't quite follow what you were looking for.
Rails has webhooks you can use to intercept emails and redirect them. You'll want to use an environment different than production.
The test environment is typically used for automated testing, to keep things clear you might want to consider setting up a new environment (eg: staging).
To create a new environment just create a new file in config/environments/ and give it a suitable name - eg: staging.rb
You can then call Rails.env.staging? where ever you like.
Anyway back to the main event...
To intercept the emails first create an intercept class:
class StagingEmailInterceptor
def self.delivering_email(message)
message.to = ['my#email.com']
end
end
and then create an initializer file, eg:
config/initializers/staging_email_interceptor.rb
and inside do this:
if Rails.env.staging?
ActionMailer::Base.register_interceptor(StagingEmailInterceptor)
end
That way all emails sent in the staging environment will be sent to your email.

Initializing Gem-Specific variables information in Ruby On Rails

I am working right now on a Rails 4.0 application (using Ruby 2.0.0).
I would like to interact with Jenkins using jenkins_api_client gem, from multiple pages of my Rails application.
This gem generally using a #client parameter, which is initialized to contain the credentials and other information of the Jenkins server.
This parameter in initialized using something like this:
#client = JenkinsApi::Client.new(:server_ip => '0.0.0.0',
:username => 'somename', :password => 'secret password')
Once initialized, I would like to access this parameter and run multiple sub-routines on it.
This initialization takes time, and I really want to avoid doing this process every time one of the clients would like to use this gem functionality, such as:
# Get a filtered list of jobs from the server
jobs_to_filter = "^test_job.*"
jobs = #client.job.list(jobs_to_filter)
So, I hope to do this only once- when the rails server starts.
I would like to use this parameter from multiple pages of my app, possibly with threaded solution further down the road (not critical at the moment).
Can anyone recommend how to achieve this?
I'd appreciate an answer which is consistent with Rails convention.
Thanks a lot!
as example you could create something like that:
module JenkinsApi
class Client
class << self
attr_reader :instance, :config
def configure(&block)
#config = OpenStruct.new
block.call #config
end
def instance
#instance ||= JenkinsApi::Client.new #config
end
end
end
end
which allow you write in initializer:
JenkinsApi::Client.configure do |config|
config.server_ip = '0.0.0.0'
config.username = 'somename'
config.password = 'secret password'
end
and then use it like: JenkinsApi::Client.instance.job.list(...

Disable certain emails in ActionMailer

I would like to turn off certain emails in development and on test/staging servers, but keep sending them in production. What I currently do is set the default "to" address for these administrative mails to blank:
default :to => Rails.env.production? ? "admin-list#sharethevisit.com" : ""
However, this puts stack traces in my development log when I'm testing the user mails which should be sending.
Is there a more effective way of disabling certain emails based on the current environment? I tried checking in the functions themselves, but is not ideal because I have to change each function, plus it doesn't actually work... it just fails to set the needed #account variable before rendering the email and creating a different stack trace.
def user_registered_notify_email(account)
if Rails.env.production?
#account = account
mail(:subject => "New user registered: #{#account.full_name}")
end
end
I usually use mail interceptors as described here: http://asciicasts.com/episodes/206-action-mailer-in-rails-3
I can't remember where I found this to credit the author but this is how I redirected email in development mode. Create a new file in RAILS_ROOT/config/initializers for this. DEFAULT_DEV_EMAIL_OVERRIDE is defined in our main site config with other static values.
if Rails.env.development?
if Rails.version =~ /^2\./
class ActionMailer::Base
def create_mail_with_overriding_recipients
mail = create_mail_without_overriding_recipients
mail.to = DEFAULT_DEV_EMAIL_OVERRIDE
mail
end
alias_method_chain :create_mail, :overriding_recipients
end
elsif Rails.version =~ /^3\./
if Rails.env.development?
class OverrideMailRecipient
def self.delivering_email(mail)
mail.to = DEFAULT_DEV_EMAIL_OVERRIDE
end
end
ActionMailer::Base.register_interceptor(OverrideMailRecipient)
end
end
end
Consider using an interceptor to set Mail::Message#perform_deliveries to false:
class NeverDeliverInterceptor
def self.delivering_email(message)
message.perform_deliveries = false
end
end
if !Rails.env.production?
ActionMailer::Base.register_interceptor(NeverDeliverInterceptor)
end
See API doc for source & other usage.

how can you filter/block outgoing email addresses with rails 2.x actionmailer?

for non-production rails 2.x environments i want to block/filter any outgoing emails that aren't addressed to people in my organization (e.g. "*#where-i-work.com").
please note, i don't want to block email entirely - i know i can just write them to the logs in test mode - i need emails to internal employees to be delivered.
thanks.
You could try extending the Mail::Message.deliver function in your environment.rb file - something like (not tested - just demo code!):
class Mail::Message
def deliver_with_recipient_filter
self.to = self.to.to_a.delete_if {|to| !(to =~ /.*#where-i-work.com\Z/)} if RAILS_ENV != production
self.deliver_without_recipient_filter unless self.to.blank?
end
alias_method_chain :deliver, :recipient_filter
end
Note that this id for Rails 3 - I think all versions of Rails 2 use TMail instead of Mail, so you'll need to override something else if you're not using Rails 3.
Hope this helps!
based on #Xavier's rails 3 proposal i was able to get it working in rails 2:
class ActionMailer::Base
def deliver_with_recipient_filter!(mail = #mail)
unless 'production' == Rails.env
mail.to = mail.to.to_a.delete_if do |to|
!to.ends_with?('where-i-work.com')
end
end
unless mail.to.blank?
deliver_without_recipient_filter!(mail)
end
end
alias_method_chain 'deliver!'.to_sym, :recipient_filter
end

Can I specify a different recipient for an ActionMailer email based on the environment?

I'm wondering if it's possible to configure a Rails email derived from ActionMailer to send to a different recipient based on the environment. For example, for development I'd like it to send mail to my personal email so I don't clog up our company email account with "Testing" emails; for production however I want it to use the real address.
How can I achieve this?
The mail_safe plugin might be a little over kill.
A simple initializer will do
Rails 2.x
if Rails.env == 'development'
class ActionMailer::Base
def create_mail_with_overriding_recipients
mail = create_mail_without_overriding_recipients
mail.to = "mail#example.com"
mail
end
alias_method_chain :create_mail, :overriding_recipients
end
end
Rails 3.x
if Rails.env == 'development'
class OverrideMailReciptient
def self.delivering_email(mail)
mail.to = "mail#example.com"
end
end
ActionMailer::Base.register_interceptor(OverrideMailReciptient)
end
By default the development environment isn't setup to actually send emails (it just logs them).
Setting up alternate accounts can be done in many different ways. You can either use some logic in your mailer like so...
recipients (Rails.env.production? ? "email#company.com" : "test#non-company.org")
Or you can define the recipient as a constant in the environment files like so:
/config/environment/production.rb
EMAIL_RECIPIENT = "email#company.com"
/config/environment/development.rb
EMAIL_RECIPIENT = "test#non-company.org"
and then use the constant in your mailer. example:
recipients EMAIL_RECIPIENT
Also, there are several plugins that do this. The best one that I've found of the three I looked at was mail_safe.

Resources