web-dev-qa-db-fra.com

Rails - Mail, obtenir le corps en texte brut

Étant donné: message = Mail.new(params[:message])

comme on le voit ici: http://docs.heroku.com/cloudmailin

Il montre comment obtenir le message.body en HTML, comment obtenir la version en clair/texte?

Merci

37
AnApprentice

Le code ci-dessus:

message = Mail.new(params[:message])

créera une nouvelle instance de mail gem à partir du message complet. Vous pouvez ensuite utiliser n’importe laquelle des méthodes de ce message pour obtenir le contenu. Vous pouvez donc obtenir le contenu brut en utilisant:

message.text_part

ou le HTML avec

message.html_part

Ces méthodes vont simplement deviner et trouver la première partie dans un message en plusieurs parties de type de contenu text/plain ou text/html. CloudMailin les fournit également à titre de méthodes pratiques toutefois via params [: plain] et params [: html]. Il convient de rappeler que le message n’est jamais garanti d’avoir une partie simple ou HTML. Il peut être intéressant d’utiliser quelque chose comme ce qui suit pour être sûr:

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

Notez également qu'il est important d'extraire le contenu du message lorsque vous utilisez ces méthodes et de vous assurer que la sortie est codée dans la méthode de codage souhaitée (comme UTF-8).

63
Steve Smith

Qu'est-ce que Mail?

La message définie dans la question semble être une instance de la même classe Mail ou Mail::Message, qui est également utilisée dans ActionMailer::Base ou dans le mailman gem

Je ne suis pas sûr de savoir où cela est intégré dans Rails, mais Steve Smith a souligné que cela est défini dans le mail gem .

Extraire une pièce d'un email en plusieurs parties

Dans le readme de la gemme, il y a une section example sur la lecture d'emails en plusieurs parties .

Outre les méthodes html_part et text_part, qui trouvent simplement la première partie du type mime correspondant , vous pouvez accéder aux parties, les parcourir en boucle et les filtrer selon les critères.

message.parts.each do |part|
  if part.content_type == 'text/plain'
    # ...
  elsif part.content_type == 'text/html'
    # ...
  end 
end

Le Mail::Part est documenté ici

Problèmes d'encodage

Selon la source du courrier reçu, des problèmes d'encodage peuvent survenir. Par exemple, Rails pourrait identifier le type de codage incorrect. Si, alors, on essaie de convertir le corps en UTF-8 afin de le stocker dans la base de données (body_string.encode('UTF-8')), des erreurs de codage telles que 

Encoding::UndefinedConversionError - "\xFC" from ASCII-8BIT to UTF-8

(comme dans cette SO question ).

Afin de contourner ce problème, on peut lire le jeu de caractères de la partie message et dire à Rails quel était ce jeu de caractères avant de l'encoder en UTF-8:

encoding = part_to_use.content_type_parameters['charset']
body = part_to_use.body.decoded.force_encoding(encoding).encode('UTF-8')

Ici, la méthode decoded supprime les lignes d'en-tête, comme indiqué dans la section de codage du fichier readme de la gemme mail .

EDIT: Problèmes de codage difficiles

S'il y a vraiment des problèmes de codage difficiles à résoudre, jetez un coup d'œil à l'excellent charlock_holmes gem .

Après avoir ajouté cette gemme à la Gemfile, il existe un moyen plus fiable de convertir les encodages de courrier électronique, à l'aide de la méthode detect_encoding, qui est ajoutée à Strings par cette gemme.

J'ai trouvé utile de définir une méthode body_in_utf8 pour les messages électroniques. (Mail::Part hérite également de 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

Résumé

# 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: Ou, après avoir défini une méthode body_in_utf8, comme ci-dessus, identique à one-liner:

(message.html_part || message.text_part || message).body_in_utf8
45
fiedl
email = Mail.new(params[:message])
text_body = (email.text_part || email.html_part || email).body.decoded

J'utilise cette solution sur RedmineCRM Helpdesk plugin

13
Kirill Bezrukov

Je crois que si vous appelez message.text_part.body.decoded, vous obtiendrez le convertir en UTF-8 pour vous par la gemme du courrier, la documentation n’est cependant pas claire à 100%.

3

Enregistrer le format de corps HTML dans Rails USE <% = @ email.body.html_safe%> Cela enverra le texte écrit dans l’éditeur de texte de messagerie électronique tel quel.

0
Dhanshree