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.



120
121
122
123
124
125
# File 'lib/astrotrain/message.rb', line 120

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
105
106
107
108
109
110
# File 'lib/astrotrain/message.rb', line 90

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)
      parsed[:email] = header[0].address
    else
      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



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



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

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

Instance Method Details

#header(key) ⇒ Object



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/astrotrain/message.rb', line 203

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



220
221
222
223
224
225
226
227
228
229
# File 'lib/astrotrain/message.rb', line 220

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



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

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

#message_idObject



181
182
183
# File 'lib/astrotrain/message.rb', line 181

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.



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

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



167
168
169
# File 'lib/astrotrain/message.rb', line 167

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

#recipients_from_delivered_toObject



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

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



163
164
165
# File 'lib/astrotrain/message.rb', line 163

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

#recipients_from_toObject



148
149
150
# File 'lib/astrotrain/message.rb', line 148

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

#senderObject



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

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

#subjectObject



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

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