Учитывая: message = Mail.new(params[:message])
как показано здесь: http://docs.heroku.com/cloudmailin
В нем показано, как получить message.body как HTML, как вам получить версию plain/text?
Спасибо
Учитывая: message = Mail.new(params[:message])
как показано здесь: http://docs.heroku.com/cloudmailin
В нем показано, как получить message.body как HTML, как вам получить версию plain/text?
Спасибо
Код выше:
message = Mail.new(params[:message])
создаст новый экземпляр почтового камня из полного сообщения. Затем вы можете использовать любой из методов этого сообщения, чтобы получить контент. Поэтому вы можете получить простой контент, используя:
message.text_part
или HTML с
message.html_part
Эти методы будут только догадываться и находить первую часть в многостраничном сообщении типа text/plain или text/html. CloudMailin также предоставляет эти методы удобства, но через params [: plain] и params [: html]. Стоит помнить, что в сообщении никогда не гарантируется наличие простой или html-части. Возможно, стоит упомянуть следующее:
plain_part = message.multipart? ? (message.text_part ? message.text_part.body.decoded : nil) : message.body.decoded
html_part = message.html_part ? message.html_part.body.decoded : nil
В качестве побочного примечания также важно извлечь кодировку содержимого из сообщения при использовании этих методов и убедиться, что вывод закодирован в желаемый способ кодирования (например, UTF-8).
Mail
?Определенный в вопросе message
является экземпляром того же класса Mail
или Mail::Message
, который также используется в ActionMailer::Base
или в почтовый камень.
Я не уверен, где это интегрировано в рельсы, но Стив Смит указал, что это определено в почтовый камень.
В окне gem readme есть фрагмент при чтении многостраничных писем.
Помимо методов html_part
и text_part
, которые просто найдут первую часть соответствующего типа mime, можно получить доступ и петля через детали вручную и фильтровать по критериям по мере необходимости.
message.parts.each do |part|
if part.content_type == 'text/plain'
# ...
elsif part.content_type == 'text/html'
# ...
end
end
Mail::Part
описанный здесь.
В зависимости от источника полученной почты могут возникнуть проблемы с кодировкой. Например, рельсы могут идентифицировать неправильный тип кодирования. Если затем попытаться преобразовать тело в UTF-8, чтобы сохранить его в базе данных (body_string.encode('UTF-8')
), могут быть ошибки в кодировке, такие как
Encoding::UndefinedConversionError - "\xFC" from ASCII-8BIT to UTF-8
(как в этот вопрос SO).
Чтобы обойти это, можно считывать кодировку из части сообщения и указывать рельсы, какая кодировка была перед кодировкой для UTF-8:
encoding = part_to_use.content_type_parameters['charset']
body = part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8')
Здесь метод decoded
удаляет строки заголовков, как показано в разделе кодировки почтового gem readme.
Если есть серьезные проблемы с кодировкой, прежний подход не решает, посмотрите на отличный драгоценный камень charlock_holmes.
После добавления этого драгоценного камня в Gemfile
существует более надежный способ преобразования кодировок электронной почты с использованием метода detect_encoding
, который добавляется к Strings этим камнем.
Мне было полезно определить метод body_in_utf8
для почтовых сообщений. (Mail::Part
также наследуется от Mail::Message
.):
module Mail
class Message
def body_in_utf8
require 'charlock_holmes/string'
body = self.body.decoded
if body.present?
encoding = body.detect_encoding[:encoding]
body = body.force_encoding(encoding).encode('UTF-8')
end
return body
end
end
end
# select the part to use, either like shown above, or as one-liner
part_to_use = message.html_part || message.text_part || message
# readout the encoding (charset) of the part
encoding = part_to_use.content_type_parameters['charset'] if part_to_use.content_type_parameters
# get the message body without the header information
body = part_to_use.body.decoded
# and convert it to UTF-8
body = body.force_encoding(encoding).encode('UTF-8') if encoding
EDIT: Или, определив метод body_in_utf8
, как показано выше, то же, что и однострочный:
(message.html_part || message.text_part || message).body_in_utf8
email = Mail.new(params[:message])
text_body = (email.text_part || email.html_part || email).body.decoded
Я использую это решение на плагине RedmineCRM Helpdesk
Я считаю, что если вы вызываете message.text_part.body.decoded, вы получите его преобразование в UTF-8 для вас почтовым камнем, документация на нем не будет на 100%.