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 = 200, num_threads = 100, num_workers = 1) ⇒ 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
# File 'lib/mail_spy/manager.rb', line 82

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

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

  count = MailSpy::Email.where(:schedule_at.lte => current_time, :sent => false, :failed => false).count
  first = MailSpy::Email.where(:schedule_at.lte => current_time, :sent => false, :failed => false).first
  division = (count / num_workers).to_i

  num_workers.times do |i|
    if MailSpy.using_delayed_job
      Email.delay.deliver_batch(current_time, first._id, (i - 1) * division, division, step, num_threads)
    else
      Email.deliver_batch(current_time, first._id, (i - 1) * division, division, step, num_threads)
    end
  end

  success = true
  return count
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)



128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/mail_spy/manager.rb', line 128

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