Module: MailSpy::Manager

Included in:
MailSpy
Defined in:
lib/mail_spy/manager.rb

Instance Method Summary collapse

Instance Method Details

#create_email(options) ⇒ Object

——————————————- CREATE EMAIL Adds a instance of a email template to the queue to send



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/mail_spy/manager.rb', line 7

def create_email(options)
  options.to_options!

  required_options = [
    :campaign, :stream, :component, :schedule_at, :subject,
    :template_values, :from, :reply_to]
  to_options = [:to, :cc, :bcc]

  # Ensure that we have the required options
  required_options.each { |ro| raise "create_email call missing #{ro}" unless options.include? ro }

  # Ensure that the campaign, stream and component are not blank
  # These keys are used to define the s3 paths for the templates
  [:campaign, :stream, :component].each { |key| raise "##{key} can't be blank" if options[key].blank? }

  # Make sure we have someone to send to and its not blank
  has_sender = to_options.select { |option| options[option].present? }.present?
  raise "Email instance has no sender (to,cc,bcc were all blank)" unless has_sender


  # Make sure that all options passed map to a accessor so we don't errantly
  # think we are passing something correctly and really its getting silently
  # ignored
  options.keys.each do |option|
    unless MailSpy::Email.method_defined? "#{option}=".intern
      raise "MailSpy::Email doesn't have #{option} as a setter '"
    end
  end

  # Ensure that a esp (forced or random) exists for the email
  forced_esp = options[:email_service_provider]
  if forced_esp.present?
    raise "No esp configured with name: #{forced_esp}" if MailSpy.esps[forced_esp].blank?
  else
    raise "No esps configured" if MailSpy.esps.blank?
    esp_key = MailSpy.esps.keys[rand(MailSpy.esps.keys.count)]
    options[:email_service_provider] = esp_key
  end

  # Google Analytics aupport for automatic population of utm_tokens
  esp = MailSpy.esps[options[:email_service_provider]]
  if esp.options[:enable_auto_google_analytics].present?
    options[:utm_source] ||= 'mailspy'
    options[:utm_medium] ||= 'email'
    options[:utm_campaign] ||= options[:campaign]
    options[:utm_term] ||= options[:stream]
    options[:utm_content] ||= options[:component]
  end

  #Create the email
  email = MailSpy::Email.new(options)

  # Ensure we have the template for the email on s3
  raise "Missing html template" unless email.html_erb.present?
  raise "Missing text template" unless email.text_erb.present?

  email.save!

  # Enable sendgrid specific enhancements
  # Must happen after the email has been saved for the id
  # TODO test this works
  if esp.options[:enable_sendgrid_event_tracking].present?
    header = MailSpy::Sendgrid::SmtpApiHeader.new
    header.setUniqueArgs({:eid => email.id.to_s})
    email.headers = {'X-SMTPAPI' => header.asJSON}.merge(email.headers)
    email.save!
  end

  email
end

#send_outstanding_emails(step = 100, num_threads = 50) ⇒ Object

——————————————- SEND OUTSTANDING EMAILS Batches through all the emails that were scheduled and have come due sends them out (step many at a time). Don’t thread this method, instead use the parameters to control concurrency



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/mail_spy/manager.rb', line 82

def send_outstanding_emails(step=100, num_threads=50)
  success = false
  raise "No Email service providers installed" unless MailSpy.esps.present?

  return if MailSpy::ProcessLog.currently_processing?
  current_process = MailSpy::ProcessLog.create!(
    {
      :start => Time.now,
      :running => true,
    })

  wq = WorkQueue.new(num_threads, step*2)
  current_time = DateTime.now
  offset = 0
  processed = 0

  # Helper function for setting present values
  def set_if_present(email, pony_hash, pony_key, email_key=nil)
    email_key = pony_key if email_key.nil?
    value = email.send("#{email_key}")
    pony_hash[pony_key] = value if value.present?
  end

  while true
    emails = MailSpy::Email.
      limit(step).offset(offset).asc(:_id).
      where(:schedule_at.lte => current_time, :sent => false, :failed => false).all
    break if emails.count <= 0 #returns enumerator which is never blank
    emails.each do |email|
      processed += 1
      wq.enqueue_b do
        MailSpy.using_delayed_job ? email.delay.deliver : email.deliver
      end
    end

    # We must join here otherwise the next loop email lookup will be in a
    # race condition with the results of our worker_queue.
    wq.join

    offset += step
  end

  success = true
  return processed

ensure
  if current_process
    end_time = Time.now
    current_process.end = end_time
    current_process.seconds_elapsed = end_time.to_i - current_process.start.to_i
    current_process.running = false
    current_process.success = success
    current_process.save!
  end
end

#track_action(email_id, action_type, details = {}, count = 1) ⇒ Object

——————————————- TRACKING MailSpy will automatically track opens and clicks if the tracking bugs and track_link helpers are used. This action allows tracking of arbitrary actions. Please be careful to standardize on action names email_id: The id from the MailSpy::Email record action_type: String denoting the action that occured details: Hash of any details of that action (again strive for standards) count: how many of this action occurred (defaults to 1)



147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/mail_spy/manager.rb', line 147

def track_action(email_id, action_type, details={}, count=1)
  raise "track_action missing email_id" if email_id.blank?
  raise "track_Action missing action_type" if action_type.blank?

  hash ={}
  hash[:action_type] = action_type
  hash[:count] = count
  hash[:details] = details if details.present? && details.kind_of?(Hash)

  # Save it up
  email = MailSpy::Email.find(email_id)
  email.actions.create!(hash)
end