При обработке ответа по электронной почте, как я могу игнорировать какие-либо особенности и историю почтового клиента?

У меня есть приложение rails, которое обрабатывает входящие электронные письма через IMAP. В настоящее время используется метод, который ищет части объекта TMail для заданного content_type:

def self.search_parts_for_content_type(parts, content_type = 'text/html')
    parts.each do |part|
      if part.content_type == content_type
        return part.body
      else
        if part.multipart?
          if body = self.search_parts_for_content_type(part.parts, content_type)
            return body
          end
        end
      end
    end

    return false
 end

Эти электронные письма, как правило, являются ответом на html-письмо, которое оно разослало в первую очередь. (Исходное исходящее электронное письмо никогда не бывает одинаковым.) Основной текст, возвращаемый описанным выше методом, содержит полную историю электронного письма, и я хотел бы просто разобрать текст ответа.

  1. Мне интересно, разумно ли размещать некоторый текст «---пожалуйста, ответьте над этой строкой---» в верхней части письма, как я видел в приложении 37 signal.

  2. Есть ли другой способ игнорировать специфичные для клиента дополнения к электронной почте, кроме написания множества регулярных выражений (которые я еще не пробовал) для каждого почтового клиента? Все они, кажется, прикрепляют свой собственный бит в верхней части любых ответов.


person tsdbrown    schedule 05.05.2009    source источник


Ответы (2)


Мне нужно разобрать ответ по электронной почте по проекту, над которым я сейчас работаю. В итоге я использовал сопоставление с образцом для идентификации части ответа, чтобы пользователям не пришлось беспокоиться о том, куда вставить свой ответ.

Хорошая новость заключается в том, что реализация действительно не слишком сложна. Сложная часть — просто протестировать все различные почтовые клиенты и службы, которые вы хотите поддерживать, и выяснить, как идентифицировать каждый из них. Как правило, вы можете использовать либо идентификатор сообщения, либо заголовок X-Mailer или Return-Path, чтобы определить, откуда пришло входящее электронное письмо.

Вот метод, который берет объект TMail, извлекает ответную часть сообщения и возвращает ее вместе с почтовым клиентом/службой, с которой оно было отправлено. Предполагается, что у вас есть исходное сообщение From: имя и адрес в константах FROM_NAME и FROM_ADDRESS.

def find_reply(email)
  message_id = email.message_id('')
  x_mailer = email.header_string('x-mailer')

  # For optimization, this list could be sorted from most popular to least popular email client/service
  rules = [
    [ 'Gmail', lambda { message_id =~ /.+gmail\.com>\z/}, /^.*#{FROM_NAME}\s+<#{FROM_ADDRESS}>\s*wrote:.*$/ ],
    [ 'Yahoo! Mail', lambda { message_id =~ /.+yahoo\.com>\z/}, /^_+\nFrom: #{FROM_NAME} <#{FROM_ADDRESS}>$/ ],
    [ 'Microsoft Live Mail/Hotmail', lambda { email.header_string('return-path') =~ /<.+@(hotmail|live).com>/}, /^Date:.+\nSubject:.+\nFrom: #{FROM_ADDRESS}$/ ],
    [ 'Outlook Express', lambda { x_mailer =~ /Microsoft Outlook Express/ }, /^----- Original Message -----$/ ],
    [ 'Outlook', lambda { x_mailer =~ /Microsoft Office Outlook/ }, /^\s*_+\s*\nFrom: #{FROM_NAME}.*$/ ],

    # TODO: other email clients/services

    # Generic fallback
    [ nil, lambda { true }, /^.*#{FROM_ADDRESS}.*$/ ]
  ]

  # Default to using the whole body as the reply (maybe the user deleted the original message when they replied?)
  notes = email.body
  source = nil

  # Try to detect which email service/client sent this message
  rules.find do |r|
    if r[1].call
      # Try to extract the reply.  If we find it, save it and cancel the search.
      reply_match = email.body.match(r[2])
      if reply_match
        notes = email.body[0, reply_match.begin(0)]
        source = r[0]
        next true
      end
    end
  end

  [notes.strip, source]
end
person Keith Platfoot    schedule 06.05.2009

Я думаю, вы застрянете на этом. Недавно я сам кое-что делал с электронными письмами в TMail, и обычно вы обнаружите, что электронное письмо, имеющее HTML-часть, обычно имеет следующую структуру:

part 1 - multipart/mixed
  sub part 1 - text/plain
  sub part 2 - text/html
end

Почтовые клиенты, с которыми я работал с Outlook и Gmail, генерируют ответы в этом формате, и они просто цитируют исходное электронное письмо, встроенное в ответ. Сначала я думал, что «старые» части исходного электронного письма будут отдельными частями, но на самом деле это не так — старая часть просто объединена с ответной частью.

Вы можете найти часть строки, которая начинается «От:» (поскольку большинство клиентов обычно размещают заголовок в верхней части исходного текста электронной почты с подробным описанием того, кто его отправил и т. д.), но это, вероятно, не гарантируется.

На самом деле я не вижу ничего плохого в --- пожалуйста, ответьте выше этой строки --- как правило, это не так агрессивно и может сделать вещи намного проще.

person Stephen ODonnell    schedule 05.05.2009
comment
Спасибо за ваш ответ, я поиграл с несколькими вариантами входящих электронных писем, включая электронные письма с вложениями. Я нашел ту же установку, что и вы упомянули. Как вы говорите, кажется, ничего не гарантировано. Мне кажется глупым, что сопоставление с образцом — единственный способ продолжать. Даже с --- ответом выше здесь --- строкой вам все равно нужно обрабатывать особенности почтового клиента, так как это, естественно, все равно идет выше строки :( - person tsdbrown; 06.05.2009