1module EmailDelivery |
|
2 # Send a single email to a recipient informing them about a petition that they have signed |
|
3 # Implemented as a custom job rather than using action mailers #deliver_later so we can do |
|
4 # extra checking before sending the email |
|
6 extend ActiveSupport::Concern |
|
8 PERMANENT_FAILURES = [ |
|
9 Net::SMTPFatalError, |
|
10 Net::SMTPSyntaxError |
|
11 ]
|
|
13 TEMPORARY_FAILURES = [ |
|
14 Net::SMTPAuthenticationError, |
|
15 Net::OpenTimeout, |
|
16 Net::SMTPServerBusy, |
|
17 Errno::ECONNRESET, |
|
18 Errno::ECONNREFUSED, |
|
19 Errno::ETIMEDOUT, |
|
20 Timeout::Error, |
|
21 EOFError, |
|
22 SocketError |
|
23 ]
|
|
25 included do |
|
26 before_perform :set_appsignal_namespace |
|
28 attr_reader :signature, :timestamp_name, :petition, :requested_at |
|
29 queue_as :low_priority |
|
31 rescue_from *PERMANENT_FAILURES do |exception| |
|
32 log_exception(exception)
|
|
33 end |
|
35 rescue_from *TEMPORARY_FAILURES do |exception| |
|
36 log_exception(exception)
|
|
37 retry_job
|
|
38 end |
|
39 end |
|
|
41 def perform(**args) |
42 @signature = args[:signature] |
|
43 @petition = args[:petition] |
|
44 @requested_at = args[:requested_at].in_time_zone |
|
45 @timestamp_name = args[:timestamp_name] |
|
47 if can_send_email? |
|
48 send_email
|
|
49 record_email_sent
|
|
50 end |
|
51 end |
|
53 private
|
|
|
55 def log_exception(exception) |
56 logger.info(log_message(exception))
|
|
57 end |
|
|
59 def log_message(exception) |
60 "#{exception.class.name} while sending email for #{self.class.name} to: #{signature.email} for #{petition.action}" |
|
61 end |
|
|
63 def can_send_email? |
64 petition_has_not_been_updated? && email_not_previously_sent?
|
|
65 end |
|
|
67 def send_email |
68 create_email.deliver_now
|
|
69 end |
|
|
71 def mailer |
72 case petition |
|
73 when Archived::Petition |
|
74 Archived::PetitionMailer |
|
75 when Petition |
|
76 PetitionMailer |
|
77 else |
|
78 raise ArgumentError, "Unknown petition type: #{petition.class}" |
|
79 end |
|
80 end |
|
|
82 def create_email |
83 raise NotImplementedError.new "Including classes must implement #create_email method" |
|
84 end |
|
|
86 def record_email_sent |
87 signature.set_email_sent_at_for timestamp_name, to: petition_timestamp |
|
88 end |
|
|
90 def petition_timestamp |
91 petition.get_email_requested_at_for(timestamp_name)
|
|
92 end |
|
94 # We do not want to send the email if the petition has been updated |
|
95 # As email sending is enqueued straight after a petition has been updated |
|
|
96 def petition_has_not_been_updated? |
97 (petition_timestamp - requested_at.in_time_zone).abs < 1 |
|
98 end |
|
100 # Have we already sent an email for this petition version? |
|
101 # If we have then the timestamp for the signature will match the timestamp for the petition |
|
|
102 def email_not_previously_sent? |
103 # check that the signature is still in the list of signatures |
|
104 petition.signatures_to_email_for(timestamp_name).where(id: signature.id).exists? |
|
105 end |
|
|
107 def set_appsignal_namespace |
108 Appsignal.set_namespace("email") |
|
109 end |
|
110end |