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.



122
123
124
125
126
127
# File 'lib/astrotrain/message.rb', line 122

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

#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.



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

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

.parse_email_address(email) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/astrotrain/message.rb', line 91

def self.parse_email_address(email)
  return {} if email.blank?
  begin
    header = TMail::Address.parse(email)
    parsed = {:name => header.name}
    if header.is_a?(TMail::AddressGroup)
      header = header[0]
    end
    if !header.blank?
      parsed[:email] = header.address
    end
    parsed
  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



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

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
58
# 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
rescue Astrotrain::ProcessingCancelled
end

.receive_file(path) ⇒ Object

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



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

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



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

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

Instance Method Details

#attachmentsObject



195
196
197
# File 'lib/astrotrain/message.rb', line 195

def attachments
  @attachments ||= process_message_body(:attachments)
end

#header(key) ⇒ Object



203
204
205
# File 'lib/astrotrain/message.rb', line 203

def header(key)
  headers[key]
end

#headersObject



207
208
209
210
211
212
213
214
215
216
# File 'lib/astrotrain/message.rb', line 207

def headers
  @headers ||= begin
    h = {}
    @mail.header.each do |key, value|
      next if self.class.skipped_headers.include?(key)
      h[key] = read_header(key) 
    end
    h
  end
end

#htmlObject



191
192
193
# File 'lib/astrotrain/message.rb', line 191

def html
  @html ||= process_message_body(:html)
end

#message_idObject



183
184
185
# File 'lib/astrotrain/message.rb', line 183

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

#rawObject



199
200
201
# File 'lib/astrotrain/message.rb', line 199

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.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/astrotrain/message.rb', line 132

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

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

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

#recipients_from_bodyObject



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

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

#recipients_from_delivered_toObject



154
155
156
157
158
159
160
161
162
163
# File 'lib/astrotrain/message.rb', line 154

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



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

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

#recipients_from_toObject



150
151
152
# File 'lib/astrotrain/message.rb', line 150

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

#senderObject



173
174
175
# File 'lib/astrotrain/message.rb', line 173

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

#subjectObject



177
178
179
180
181
# File 'lib/astrotrain/message.rb', line 177

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