I'm relatively inexperienced and trying to maintain a web app built with Rails 2.3.X and Ruby 1.8.7. Users who create accounts with the app are supposed to receive an automated email with an "activation" link, which is how they confirm that they actually have access to the email address they want to register.
I have found that some, but not all, of my users are getting this activation email. When they don't get the email in their inbox, the email also does not appear in their spam folders.
My suspicion is that the problem has to do with the formatting of the email; maybe some email providers don't like the format and filter it automatically.
I am not sure what information I need to provide to investigate the cause, but here are some places that I thought made sense:
Web form (user can request a new activation link)
<h3>Resend activation link?</h3>
<form action="/send_activation" method="post">
<input name="authenticity_token" type="hidden" value="<%= form_authenticity_token %>" />
<p class="field">
<label for="user_email">Email Address</label>
<input class="login" id="user_email" name="user[email]" size="45" type="text" />
</p>
<div class="clear"></div>
<input name="commit" type="submit" value="submit" />
</form>
sessions_controller.rb
def send_activation
return unless request.post?
@title = "Send Activation Link"
@user = User.find_by_email(params[:user][:email])
if @user && @user.activated_at.blank?
UserMailer.deliver_signup_notification(@user)
redirect_to login_url
flash[:notice] = "Activation link sent."
else
flash[:notice] = "Could not find your email address. Try another."
end
end
user_mailer.rb
class UserMailer < ActionMailer::Base
def activation(user)
setup_email(user)
@subject += 'Your account has been activated!'
@body[:url] = "http://MYWEBSITE/"
end
integral_mailer.rb
module IntegralMailer
def perform_delivery_integral_mailer(mail)
destinations = mail.destinations
mail.ready_to_send
helo = smtp_settings[:helo] || "localhost.localdomain"
ActionMailer::Base::INTEGRAL_MAILER_SERVER.send_mail(helo, mail.from, destinations, mail.encoded)
end
end
integral_mailer_server.rb
require 'net/smtp'
require 'logger'
require 'fileutils'
require 'mx_lookup'
class IntegralMailerServer
include FileUtils
def self.reloadable?; false; end
def initialize(opts={})
@times_to_try_busy_host = opts[:times_to_try_busy_host] || 2
initialize_log( (opts[:age_log_file] || 'daily'), opts[:log_path] )
end
def send_mail(helo_domain, from_email, destination_emails, data)
t = Thread.new do
destination_emails.each do |dest_email|
mx_records = MXLookup.for_email(dest_email)
mx_records.each do |mx_record|
begin
do_delivery(mx_record[:host], helo_domain, data, from_email, dest_email) and break
rescue Net::SMTPFatalError => e
log_fatal_delivery(dest_email, mx_record[:host], e.message) and break
rescue Net::SMTPServerBusy => e
log_delayed_delivery(dest_email, mx_record[:host], e.message)
# there has to be a better method to use for this
unless (mx_records.find_all { |r| r == mx_record }).size >= @times_to_try_busy_host
mx_records << mx_record
else
log_fatal_delivery(dest_email, mx_record[:host], e.message)
end
rescue => e
if mx_records.last == mx_record
log_fatal_delivery(dest_email, mx_record[:host], e.message)
else
log_delayed_delivery(dest_email, mx_record[:host], e.message)
end
end
end # mx_records.each
end # destination_emails.each
end # Thread.new
end # send_mail
private
def do_delivery(host, helo, data, from_email, dest_email)
Net::SMTP.start(host, 25, helo) do |smtp|
smtp.send_message data, from_email, dest_email
log_successful_delivery(dest_email, host)
end; true
end
def log_delayed_delivery(email, host, reason)
msg = "Message NOT sent to #{email} via #{host}\n --> #{reason.strip}\n" +
" --> However, I'm not giving up just yet."
@log.warn(msg); msg
end
def log_fatal_delivery(email, host, reason)
msg = "Message NOT sent to #{email} via #{host}\n --> #{reason.strip}\n" +
" --> I'm giving up delivery of this message."
@log.fatal(msg); msg
end
def log_successful_delivery(email, host)
msg = "Message sent to #{email} via #{host}"
@log.info(msg); msg
end
def initialize_log(age_log_file='daily', log_path=nil)
if log_path
@log = Logger.new(log_path, age_log_file)
else
if defined?(RAILS_ROOT)
@log = Logger.new("#{RAILS_ROOT}/log/integral_mailer.log", age_log_file) rescue Logger.new(STDOUT)
else
@log = Logger.new(STDOUT)
end
end
@log.info "Initializing"
end
end