# encoding: utf-8 # # = Email Handler # # This class is used to send all email. Note that it is just a collection of # class methods; it is never instantiated. It is a subclass of # ActionMailer::Base. See also QueuedEmail for more information about how # queuing works and how all the email-related classes and subclasses are # related. # # == Class methods # # admin_request:: Ask project admins for admin privileges on project. # author_request:: Ask reviewers for authorship credit. # comment:: Notify user of comment on their object. # commercial_inquiry:: User asking user about an image. # consensus_change:: Notify user of name change of their obs. # denied:: Email sent to Nathan when sign-up is denied. # email_features:: Mass-mailing about new features. # email_registration:: Verify a conference event registration. # location_change:: Notify user of change in location description. # name_change:: Notify user of change in name description. # name_proposal:: Notify user of name proposal for their obs. # naming_for_observer:: Tell observer someone is interested in their obs. # naming_for_tracker:: Notify user someone has observed a name they are interested in. # new_password:: User forgot their password. # observation_change:: Notify user of change in observation. # observation_question:: User asking user about an observation. # publish_name:: Notify reviewers that a draft has been published. # user_question:: User asking user about anything else. # verify:: Email sent to verify user's email. # webmaster_question:: User asking webmaster a question. # # == Delivery methods # # There are four delivery methods available, configurable in # config/environment.rb as: # # config.action_mailer.delivery_method = :method # # Where :method is one of these: # # smtp:: Default for production: uses the Net::SMTP ruby library. # sendmail:: We've never used this: uses /usr/sbin/sendmail. # test:: Default for unit tests: ??? # file:: Default for development: writes emails as files in # RAILS_ROOT/../mail (if this directory exists). # # == Privacy policy # # Our current policy is that a user's email address is only revealed to people # they explicitly send questions to, or to the owner of the observation they # comment on. *NOT* to third parties who are simply interested in or who have # also commented on the same observation. # ################################################################################ require 'smtp_tls' class AccountMailer < ActionMailer::Base # Ask project admins for admin privileges on project. # sender:: User asking for permission. # receiver:: Admin user. # project:: Project instance. # subject:: Subject of message (provided by user?). # message:: Content of message (provided by user). def admin_request(sender, receiver, project, subject, message) @user = receiver Locale.code = @user.locale || DEFAULT_LOCALE @subject = subject @body['subject'] = @subject @body['user'] = @user @body['sender'] = sender @body['message'] = message || '' @body['project'] = project @recipients = receiver.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = sender.email @content_type = @user.email_html ? 'text/html' : 'text/plain' @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL admin_request " + "from=#{sender.id} " + "to=#{receiver.id} " + "project=#{project.id}") end # Ask reviewers for authorship credit. # sender:: User asking for credit. # receiver:: Reviewer/admin user. # object:: NameDescription or LocationDescription on which User would like to be author. # subject:: Subject of message (provided by user?). # message:: Content of message (provided by user). def author_request(sender, receiver, object, subject, message) @user = receiver Locale.code = @user.locale || DEFAULT_LOCALE @subject = subject @body['subject'] = @subject @body['user'] = @user @body['sender'] = sender @body['message'] = message || '' @body['object'] = object @recipients = receiver.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = sender.email @content_type = @user.email_html ? 'text/html' : 'text/plain' @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL author_request " + "from=#{sender.id} " + "to=#{receiver.id} " + "object=#{object.type_tag}-#{object.id}") end # Notify user of comment on their object. # sender:: User who posted the Comment. # receiver:: Owner of target (or interested party). # target:: Object that was commented upon. # comment:: Comment that triggered this email. def comment(sender, receiver, target, comment) @user = receiver Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_comment.l(:name => target.unique_text_name) @body['subject'] = @subject @body['user'] = @user @body['sender'] = sender @body['target'] = target @body['comment'] = comment @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = (sender && receiver == target.user) ? sender.email : NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? 'text/html' : 'text/plain' @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL comment " + "from=#{sender.id} " + "to=#{receiver.id} " + "object=#{target.type_tag}-#{target.id}") end # User asking user about an image. # sender:: User asking the question. # image:: Image in question. # commercial_inquiry:: Content of message (provided by user). def commercial_inquiry(sender, image, commercial_inquiry) @user = image.user Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_commercial_inquiry.l(:name => image.unique_text_name) @body['subject'] = @subject @body['user'] = @user @body['sender'] = sender @body['image'] = image @body['message'] = commercial_inquiry || '' @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = sender.email @content_type = @user.email_html ? "text/html" : "text/plain" @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL commercial_inquiry " + "from=#{sender.id} " + "to=#{image.user_id} " + "image=#{image.id}") end # Notify user of name change of their obs. # sender:: User who voted or proposed the name that caused the change. # receiver:: Owner of the Observation (or interested third party). # observation:: Observation in question. # old_name:: Old consensus Name. # new_name:: New consensus Name. # time:: Time the change took place. def consensus_change(sender, receiver, observation, old_name, new_name, time) @user = receiver Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_consensus_change.l(:id => observation.id, :old => (old_name ? old_name.search_name : 'none'), :new => (new_name ? new_name.search_name : 'none')) @body['subject'] = @subject @body['user'] = @user @body['sender'] = sender @body['observation'] = observation @body['old_name'] = old_name @body['new_name'] = new_name @body['time'] = time @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? 'text/html' : 'text/plain' @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL consensus_change " + "from=#{sender.id} " + "to=#{receiver.id} " + "observation=#{observation.id}") end # Email sent to Nathan when sign-up is denied. # user_params:: Hash of parameters from form. def denied(user_params) Locale.code = DEFAULT_LOCALE @subject = :email_subject_denied.l @body['subject'] = @subject @body['user'] = @user @body['user_params'] = user_params @recipients = WEBMASTER_EMAIL_ADDRESS @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = ACCOUNTS_EMAIL_ADDRESS @subject = '[MO] ' + @subject.to_ascii end # Mass-mailing about new features. # user:: User we're sending announcement to. # features:: Description of changes (body of email). def email_features(user, features) @user = user Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_features.l @body['subject'] = @subject @body['user'] = @user @body['features'] = features @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? "text/html" : "text/plain" @subject = '[MO] ' + @subject.to_ascii end # Notify email given in registration of the registration # user:: User we're sending announcment to. Defaults to admin. # registration:: ConferenceRegistration object def email_registration(user, registration) event = registration.conference_event @user = user Locale.code = DEFAULT_LOCALE Locale.code = @user.locale if @user and @user.locale @subject = :email_subject_registration.l(:name => event.name) @body['registration'] = registration @body['subject'] = @subject @body['user'] = user @recipients = registration.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = WEBMASTER_EMAIL_ADDRESS @content_type = 'text/html' @content_type = 'text/plain' if @user and not @user.email_html @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL registration " + "to=#{registration.email} ") end # Notify user of change in location description. # sender:: User who changed the Location. # receiver:: Owner of the Location (or interested third party). # time:: Time the change took place. # loc:: Location in question. # desc:: LocationDescription in question. # old_loc_ver:: Version number of the Location _before_ the change. # new_loc_ver:: Version number of the Location _after_ the change (may be the same). # old_desc_ver:: Version number of the LocationDescription _before_ the change. # new_desc_ver:: Version number of the LocationDescription _after_ the change (may be the same). def location_change(sender, receiver, time, loc, desc, old_loc_version, new_loc_version, old_desc_version, new_desc_version) old_loc = loc.versions.find_by_version(old_loc_version) new_loc = loc; loc.revert_to(new_loc_version) old_desc = desc ? desc.versions.find_by_version(old_desc_version) : nil new_desc = desc; desc.revert_to(new_desc_version) if desc @user = receiver Locale.code = @user.locale || DEFAULT_LOCALE # Ideally there would be an old_loc.display_name, but I don't know where that would go old_loc_name = Location.user_name(@user, old_loc.name) @subject = :email_subject_location_change.l(:name => old_loc_name) @body['subject'] = @subject @body['user'] = @user @body['sender'] = sender @body['time'] = time @body['old_loc'] = old_loc @body['new_loc'] = new_loc @body['old_desc'] = old_desc @body['new_desc'] = new_desc @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? 'text/html' : 'text/plain' @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL location_change " + "from=#{sender.id} " + "to=#{receiver.id} " + "location=#{loc.id rescue 'nil'} " + "description=#{desc.id rescue 'nil'}") end # Notify user of change in name description. # sender:: User who changed the Name. # receiver:: Owner of the Name (or interested third party). # time:: Time the change took place. # name:: Name in question. # desc:: NameDescription in question. # old_name_ver:: Version number of the Name _before_ the change. # new_name_ver:: Version number of the Name _after_ the change (may be the same). # old_desc_ver:: Version number of the NameDescription _before_ the change. # new_desc_ver:: Version number of the NameDescription _after_ the change (may be the same). # review_status:: Current review status. def name_change(sender, receiver, time, name, desc, old_name_version, new_name_version, old_desc_version, new_desc_version, review_status) old_name = name.versions.find_by_version(old_name_version) new_name = name; name.revert_to(new_name_version) old_desc = desc ? desc.versions.find_by_version(old_desc_version) : nil new_desc = desc; desc.revert_to(new_desc_version) if desc @user = receiver Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_name_change.l(:name => (old_name ? old_name.search_name : new_name.search_name)) @body['subject'] = @subject @body['user'] = @user @body['sender'] = sender @body['time'] = time @body['old_name'] = old_name @body['new_name'] = new_name @body['old_desc'] = old_desc @body['new_desc'] = new_desc @body['review_status'] = "review_#{review_status}".to_sym.l if review_status != :no_change @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? 'text/html' : 'text/plain' @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL name_change " + "from=#{sender.id} " + "to=#{receiver.id} " + "name=#{name.id rescue 'nil'} " + "description=#{desc.id rescue 'nil'}") end # Notify user of name proposal for their obs. # sender:: User who proposed the Name. # receiver:: Owner of the Observation (or interested third party). # naming:: Naming in question. # observation:: Observation in question. def name_proposal(sender, receiver, naming, observation) @user = receiver Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_name_proposal.l(:name => naming.text_name, :id => observation.id) @body['subject'] = @subject @body['user'] = @user @body['naming'] = naming @body['observation'] = observation @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? 'text/html' : 'text/plain' @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL name_proposal " + "from=#{sender.id} " + "to=#{receiver.id} " + "naming=#{naming.id rescue 'nil'} " + "observation=#{observation.id rescue 'nil'}") end # Tell observer someone is interested in their obs. # observer:: Owner of the Observation. # naming:: Naming that was proposed that triggered this email. # notification:: Notification instance registering interest in this Name. def naming_for_observer(observer, naming, notification) sender = notification.user @user = observer Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_naming_for_observer.l @body['subject'] = @subject @body['user'] = @user @body['naming'] = naming @body['notification'] = notification @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = sender ? sender.email : NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? "text/html" : "text/plain" @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL naming_for_observer " + "from=#{sender.id rescue 'nil'} " + "to=#{@user.id rescue 'nil'} " + "naming=#{naming.id rescue 'nil'} " + "notification=#{notification.id rescue 'nil'}") end # Notify user someone has observed a name they are interested in. # tracker:: User that has created the Notification registering interest in this Name. # naming:: Naming that triggered this email. def naming_for_tracker(tracker, naming) @user = tracker Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_naming_for_tracker.l @body['subject'] = @subject @body['user'] = @user @body['observation'] = naming.observation @body['naming'] = naming @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? "text/html" : "text/plain" @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL naming_for_tracker " + "from=#{'nil'} " + "to=#{@user.id rescue 'nil'} " + "naming=#{naming.id rescue 'nil'} " + "observation=#{naming.observation.id rescue 'nil'}") end # User forgot their password. # user:: User who requested the new password. # password:: The new password (unencrypted). def new_password(user, password) @user = user Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_new_password.l @body['subject'] = @subject @body['user'] = @user @body['password'] = password @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = ACCOUNTS_EMAIL_ADDRESS @headers['Reply-To'] = NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? "text/html" : "text/plain" @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL new_password " + "to=#{@user.id rescue 'nil'}") end # Notify user of change in observation. # sender:: User who changed the Observation (should be the owner). # receiver:: Third party user who is interested in this Observation. # observation:: Observation in question. # note:: List of changed attributes (see QueuedEmail::ObservationChange). # time:: Time the change took place. def observation_change(sender, receiver, observation, note, time) @user = receiver Locale.code = @user.locale || DEFAULT_LOCALE @subject = observation ? :email_subject_observation_change.l(:name => observation.unique_text_name) : :email_subject_observation_destroy.l(:name => note).t.html_to_ascii @body['subject'] = @subject @body['user'] = @user @body['sender'] = sender @body['observation'] = observation @body['note'] = note @body['time'] = time @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? 'text/html' : 'text/plain' @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL observation_change " + "from=#{sender.id} " + "to=#{receiver.id} " + "observation=#{observation.id rescue 'nil'}") end # User asking user about an observation. # sender:: User asking the question. # observation:: Observation the question is about. # question:: The actual question (content). def observation_question(sender, observation, question) @user = observation.user Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_observation_question.l(:name => observation.unique_text_name) @body['subject'] = @subject @body['user'] = @user @body['sender'] = sender @body['observation'] = observation @body['message'] = question || '' @recipients = @user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = sender.email @content_type = @user.email_html ? "text/html" : "text/plain" @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL observation_question " + "from=#{sender.id rescue 'nil'} " + "to=#{@user.id rescue 'nil'} " + "observation=#{observation.id rescue nil}") end # Notify reviewers that a draft has been published. # publisher:: User who is publishing the draft. # receiver:: Reviewer receiving the announcement. # name:: Name whose description is being published. def publish_name(publisher, receiver, name) @user = receiver @name = name Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_publish_name.l @body['subject'] = @subject @body['user'] = receiver @body['publisher'] = publisher @body['name'] = name @recipients = receiver.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = NOREPLY_EMAIL_ADDRESS @content_type = @user.email_html ? "text/html" : "text/plain" @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL publish_name " + "from=#{publisher.id rescue 'nil'} " + "to=#{receiver.id rescue 'nil'} " + "name=#{name.id rescue nil}") end # Notify email given in registration of a change in the registration # user:: User we're sending announcment to. Defaults to admin. # before:: String describing the registration before the change. # after:: String describing the registration after the change. def update_registration(user, registration, before) event = registration.conference_event @user = user Locale.code = DEFAULT_LOCALE Locale.code = @user.locale if @user and @user.locale @subject = :email_subject_update_registration.l(:name => event.name) @body['registration'] = registration @body['before'] = before @body['subject'] = @subject @body['user'] = user @recipients = registration.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = WEBMASTER_EMAIL_ADDRESS @content_type = 'text/html' @content_type = 'text/plain' if @user and not @user.email_html @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL update_registration " + "to=#{registration.email} ") end # User asking user about anything else. # sender:: User asking the question. # user:: User receiving the question. # subject:: Subject of question (provided by user). # content:: Content of question (provided by user). def user_question(sender, user, subject, content) @user = user Locale.code = @user.locale || DEFAULT_LOCALE @subject = subject @body['subject'] = @subject @body['user'] = user @body['sender'] = sender @body['message'] = content || '' @recipients = user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = NEWS_EMAIL_ADDRESS @headers['Reply-To'] = sender.email @content_type = @user.email_html ? "text/html" : "text/plain" @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL user_question " + "from=#{sender.id rescue 'nil'} " + "to=#{user.id rescue 'nil'}") end # Email sent to verify user's email. # user:: User that just signed up. def verify(user) @user = user Locale.code = @user.locale || DEFAULT_LOCALE @subject = :email_subject_verify.l @body['subject'] = @subject @body['user'] = user @recipients = user.email @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = ACCOUNTS_EMAIL_ADDRESS @content_type = @user.email_html ? "text/html" : "text/plain" @subject = '[MO] ' + @subject.to_ascii QueuedEmail.debug_log("MAIL verify " + "to=#{user.id} email=#{user.email}") end # User asking webmaster a question. # sender:: User asking the question. # question:: Content of the question. def webmaster_question(sender, question) Locale.code = DEFAULT_LOCALE @subject = :email_subject_webmaster_question.l(:user => sender) @body['question'] = question @recipients = WEBMASTER_EMAIL_ADDRESS @bcc = EXTRA_BCC_EMAIL_ADDRESSES @from = WEBMASTER_EMAIL_ADDRESS @headers['Reply-To'] = sender @subject = '[MO] ' + @subject.to_ascii end ################################################################################ private # Set delivery_method to :file to cause this method to be called whenever # mail is sent anywhere. It just stuffs them all in ../mail/0001 etc. def perform_delivery_file(mail) path = '../mail' if File.directory?(path) count = 0; begin count += 1 if count >= 10000 raise(RangeError, "More than 10000 email files found like '#{file}'") end file = "%s/%04d" % [path, count] end while File.exists?(file) fh = File.new(file, "w") fh.write(mail) fh.close end end # Log exactly who is sending email at what times. # def log_email # File.open("#{RAILS_ROOT}/log/email-low-level.log", 'a') do |fh| # time = Time.now.strftime('%Y-%m-%d:%H:%M:%S') # # begin # raise RuntimeError # rescue RuntimeError => e # trace = e.backtrace # rescue # trace = [] # end # # type = trace[3].match(/`(\w+)'/) ? $1 : 'nil' # # caller = nil # for x in trace[4..-1] # if !x.match(/^\/usr/) # caller = x # break # end # end # # fh.puts("time=#{time} cmd=#{$0.inspect} type=#{type.inspect} " + # "caller=#{caller.inspect}") # end # end end