Class: Astrotrain::Message

Inherits:
Object
  • Object
show all
Defined in:
lib/astrotrain/message.rb

Overview

Wrapper around a TMail object

Defined Under Namespace

Classes: Attachment

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mail) ⇒ Message

Returns a new instance of Message.



114
115
116
117
118
119
# File 'lib/astrotrain/message.rb', line 114

def initialize(mail)
  @mail        = mail
  @mapping     = nil
  @attachments = []
  @recipients  = {}
end

Class Attribute Details

.archive_pathObject

Returns the value of attribute archive_path.



13
14
15
# File 'lib/astrotrain/message.rb', line 13

def archive_path
  @archive_path
end

.queue_pathObject

Returns the value of attribute queue_path.



13
14
15
# File 'lib/astrotrain/message.rb', line 13

def queue_path
  @queue_path
end

.recipient_header_orderObject

Returns the value of attribute recipient_header_order.



14
15
16
# File 'lib/astrotrain/message.rb', line 14

def recipient_header_order
  @recipient_header_order
end

.skipped_headersObject

Returns the value of attribute skipped_headers.



14
15
16
# File 'lib/astrotrain/message.rb', line 14

def skipped_headers
  @skipped_headers
end

Instance Attribute Details

#attachmentsObject (readonly)

Returns the value of attribute attachments.



10
11
12
# File 'lib/astrotrain/message.rb', line 10

def attachments
  @attachments
end

#bodyObject

Returns the value of attribute body.



9
10
11
# File 'lib/astrotrain/message.rb', line 9

def body
  @body
end

#mailObject (readonly)

Returns the value of attribute mail.



10
11
12
# File 'lib/astrotrain/message.rb', line 10

def mail
  @mail
end

Class Method Details

.parse(raw) ⇒ Object

Parses the raw email headers into a Astrotrain::Message instance.



74
75
76
# File 'lib/astrotrain/message.rb', line 74

def self.parse(raw)
  new Mail.parse(raw)
end

.parse_email_address(email) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/astrotrain/message.rb', line 90

def self.parse_email_address(email)
  return {} if email.blank?
  begin
    header = TMail::Address.parse(email)
    {:name => header.name, :email => header.address}
  rescue SyntaxError, TMail::SyntaxError
    email = email.scan(/\<([^\>]+)\>/)[0]
    if email.blank?
      return {:name => nil, :email => nil}
    else
      email = email[0]
      retry
    end
  end
end

.parse_email_addresses(value) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/astrotrain/message.rb', line 78

def self.parse_email_addresses(value)
  emails     = value.split(",")
  collection = []
  emails.each do |addr|
    addr.strip!
    next if addr.blank?
    header = parse_email_address(addr.to_s)
    collection << unescape(header[:email]) if !header[:email].blank?
  end
  collection
end

.queue(raw) ⇒ Object

Dumps the raw text into the queue_path. Not really recommended, since you should set the queue_path to the directory your incoming emails are dumped into.



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/astrotrain/message.rb', line 39

def self.queue(raw)
  filename = nil
  digest   = Digest::SHA1.hexdigest(raw)
  while filename.nil? || File.exist?(filename)
    filename = File.join(queue_path, Digest::SHA1.hexdigest(digest + rand.to_s))
  end
  File.open filename, 'wb' do |f|
    f.write raw
  end
  filename
end

.receive(raw, file = nil) ⇒ Object

Parses the given raw email text and processes it with a matching Mapping.



52
53
54
55
56
57
# File 'lib/astrotrain/message.rb', line 52

def self.receive(raw, file = nil)
  message = parse(raw)
  Astrotrain.callback(:pre_mapping, message)
  Mapping.process(message, file)
  message
end

.receive_file(path) ⇒ Object

Processes the given file. It parses it by reading the contents, and optionally archives or removes the original file.



61
62
63
64
65
66
67
68
69
70
71
# File 'lib/astrotrain/message.rb', line 61

def self.receive_file(path)
  raw         = IO.read(path)
  logged_path = path
  if archive_path
    daily_archive_path = archive_path / Time.now.year.to_s / Time.now.month.to_s / Time.now.day.to_s
    FileUtils.mkdir_p(daily_archive_path)
    logged_path = daily_archive_path / File.basename(path)
    FileUtils.mv path, logged_path if path != logged_path
  end
  receive(raw, logged_path)
end

.unescape(s) ⇒ Object

Stolen from Rack/Camping, remove the “+” => “ ” translation



107
108
109
110
111
112
# File 'lib/astrotrain/message.rb', line 107

def self.unescape(s)
  s.gsub!(/((?:%[0-9a-fA-F]{2})+)/n){
    [$1.delete('%')].pack('H*')
  }
  s
end

Instance Method Details

#header(key) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/astrotrain/message.rb', line 197

def header(key)
  @headers ||= {}
  if !@headers.key?(key)
    @headers[key] = if self.class.skipped_headers.include?(key)
      nil
    else
      header = @mail.header[key]
      begin
        header.to_s
      rescue
        header.raw_body
      end
    end
  end
  @headers[key]
end

#headersObject



214
215
216
217
218
219
220
221
222
223
# File 'lib/astrotrain/message.rb', line 214

def headers
  @headers ||= begin
    h = {}
    @mail.header.each do |key, value|
      header_value = header(key)
      h[key] = header_value if header_value
    end
    h
  end
end

#htmlObject



186
187
188
189
190
191
# File 'lib/astrotrain/message.rb', line 186

def html
  @html ||= begin
    process_message_body
    @html
  end
end

#message_idObject



175
176
177
# File 'lib/astrotrain/message.rb', line 175

def message_id
  @message_id ||= mail.header('message-id').to_s.gsub(/^<|>$/, '')
end

#rawObject



193
194
195
# File 'lib/astrotrain/message.rb', line 193

def raw
  @mail.port.to_s
end

#recipients(order = nil) ⇒ Object

Gets the recipients of an email using the To/Delivered-To/X-Original-To headers. It’s not always straightforward which email we want when dealing with filters and forward rules.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/astrotrain/message.rb', line 124

def recipients(order = nil)
  if !@recipients.key?(order)
    order = self.class.recipient_header_order if order.blank?
    recipients = []

    parse_email_headers recipients_from_body, recipients
    order.each do |key|
      parse_email_headers(send("recipients_from_#{key}"), recipients)
    end

    recipients.flatten!
    recipients.uniq!
    @recipients[order] = recipients
  else
    @recipients[order]
  end
end

#recipients_from_bodyObject



161
162
163
# File 'lib/astrotrain/message.rb', line 161

def recipients_from_body
  @recipients_from_body ||= body.scan(/<[\w\.\_\%\+\-]+@[\w\-\_\.]+>/)
end

#recipients_from_delivered_toObject



146
147
148
149
150
151
152
153
154
155
# File 'lib/astrotrain/message.rb', line 146

def recipients_from_delivered_to
  @recipient_from_delivered_to ||= begin
    delivered = @mail['Delivered-To']
    if delivered.respond_to?(:first)
      delivered.map! { |a| a.to_s }
    else
      [delivered.to_s]
    end
  end
end

#recipients_from_original_toObject



157
158
159
# File 'lib/astrotrain/message.rb', line 157

def recipients_from_original_to
  @recipient_from_original_to ||= [@mail['X-Original-To'].to_s]
end

#recipients_from_toObject



142
143
144
# File 'lib/astrotrain/message.rb', line 142

def recipients_from_to
  @recipient_from_to ||= [@mail['to'].to_s]
end

#senderObject



165
166
167
# File 'lib/astrotrain/message.rb', line 165

def sender
  @sender ||= TMail::Unquoter.unquote_and_convert_to(@mail['from'].to_s, "utf-8")
end

#subjectObject



169
170
171
172
173
# File 'lib/astrotrain/message.rb', line 169

def subject
  @mail.subject
rescue Iconv::InvalidCharacter
  @mail.quoted_subject
end