ActionMailer: attachment con filename en UTF8

Hola gente,

Estoy tratando ficheros adjuntos que me llegan por correo y todo
parecía solucionado hasta que me llega el primer email con un adjunto
con el filename codificado con UTF8:

–part283255-boundary-640451732-560270778
Content-Transfer-Encoding: base64
Content-Type: image/jpeg
Content-Disposition: attachment; filename=“=?utf-8?B?SU1HMDAwOTkuanBn?=”

El fichero originalmente se llama: IMG00099.jpg

Y gmail lo reconstruye correctamente.

Para reproducir el error abrir este .zip[1] y pasarle el contenido a
la siguiente secuencia de script/console:
[1]
http://fernandoguillen.info/ftp/mail_image_attach_from_bb.raw_mail.zip

mail = TMail::Mail.parse( File.read( “mail_image_attach_from_bb.raw_mail” ) )
=> #<TMail::Mail port=#TMail::StringPort:id=0x139a20a bodyport=nil>
mail.attachments[0].original_filename
=> “=?utf-8?B?SU1HMDAwOTkuanBn?=”

El body lo descodifica correctamente:

–part283255-boundary-640451732-560270778
Content-Transfer-Encoding: base64
Content-Type: text/plain; charset=“Windows-1252”

DQpCbGFja0JlcnJ5IGRlIG1vdmlzdGFyLCBhbGztIGRvbmRlIGVzdOlzIGVzdOEgdHUgb2ZpY2lu
QA==

mail.body
=> “\r\nBlackBerry de movistar, allí donde estés está tu
oficin@Attachment: (unnamed)\n”

He visto esto mirando por google, pero no parece que le hayan dado
ninguna
solución:ActionMailer: attachments with utf8 filenames? - Rails - Ruby-Forum

Cualquier sugerencia es bienvenida.

f.

PD:------------

He encontrado cosas como esta:
http://dev.rubyonrails.org/ticket/6758

Que intentan resolver el mismo problema pero en los subjects.

De ahí he extraído un poco de código para parchear la carga de
attachments de un email y he añadido esto cuando se carga el
original_filename:

fguillen: 2008-09-29: descodificando utf8

TODO: hay que hacer esto mejor, porque la comprobación del formato

no está fina :slight_smile:
if file_name =~ /^=?utf-8/i
file_name = TMail::Unquoter.unquote_and_convert_to( file_name, ‘utf-8’
)
end

Fijarse en como se sabe si es utf-8… super cutre pero no encuentro
otro modo… por ahí[1] dicen que mirando el Content-Transfer-Encoding,
pero:

mail.content_transfer_encoding
=> nil

[1]
http://www.naffis.com/2006/8/14/receiving-emails-and-attachments-with-rails

2008/9/29 Fernando G. [email protected]:

mail.attachments[0].original_filename

f.
original_filename:
pero:

mail.content_transfer_encoding
=> nil

[1] http://www.naffis.com/2006/8/14/receiving-emails-and-attachments-with-rails

No he podido descargar el zip ni ver los enlaces (tengo una conexión a
internet algo limitada), pero si mal no recuerdo, el formato de
“=?encoding?foobar?=” estaba definido en alguno de los (multiples) RFC
de MIME. Con ese RFC a mano debería ser sencillo ver si el valor de un
campo coincide con el formato /=?([^?]+)?(.*)?=/ (o el RegEx que
sea) y extraer el encoding y el contenido (al que puedes aplicar esa
función unquote_and_convert_to).

Suerte.

El día 29 de septiembre de 2008 20:24, Daniel R.
Troitiño[email protected]
escribió:> No he podido descargar el zip ni ver los enlaces (tengo una conexión a

internet algo limitada),

Qué pasa que los alemanes no tienen buenas ADSLs como nosotros ? :stuck_out_tongue:

pero si mal no recuerdo, el formato de
“=?encoding?foobar?=” estaba definido en alguno de los (multiples) RFC
de MIME. Con ese RFC a mano debería ser sencillo ver si el valor de un
campo coincide con el formato /=?([^?]+)?(.*)?=/ (o el RegEx que
sea) y extraer el encoding y el contenido (al que puedes aplicar esa
función unquote_and_convert_to).

Mirando el código del Unquoter veo que tira de esa expresión regular
para extraer el enconding en que está codificado el string:

File lib/tmail/quoting.rb, line 61

def unquote_and_convert_to(text, to_charset, from_charset =
“iso-8859-1”, preserve_underscores=false)
return “” if text.nil?
text.gsub(/(.?)(?:(?:=?(.?)?(.)?(.*?)?=)|$)/) do
before = $1
from_charset = $2
quoting_method = $3
text = $4

before = convert_to(before, to_charset, from_charset) if 

before.length > 0
before + case quoting_method
when “q”, “Q” then
unquote_quoted_printable_and_convert_to(text, to_charset,
from_charset, preserve_underscores)
when “b”, “B” then
unquote_base64_and_convert_to(text, to_charset, from_charset)
when nil then
# will be nil at the end of the string, due to the nature of
# the regex used.
“”
else
raise “unknown quoting method #{quoting_method.inspect}”
end
end
end

Ver el resultado de esta regex con el filename condificado de mi
ejemplo:
http://fernandoguillen.info/ftp/rubular_regex_unquoter.png

Parece ser que lo que yo le pasa es el enconding al que quiero que me
lo convierta pues el enconding en el cual originalmente está
codificado lo coge del propio string haciendo uso de una regex como la
que enviabas.

Vale, guay, pero… 2 cosas:

  1. si el from es utf-8 (porque lo pone en el string) y el to es utf-8
    porque se lo indico yo… ¿cómo es que se parecen tan poco? (Esto de
    los enconding… digo yo que alguna vez me hará click el cerebro y lo
    entenderé… pero por ahora tengo un líooo)

  2. como sé si el string (en este caso el filename) está codificado? …
    aunque igual no hace falta… le paso el unquoter siempre y a correr:

TMail::Unquoter.unquote_and_convert_to( “IMG00099.jpg”, ‘utf-8’ )
=> “IMG00099.jpg”

No sé estoy pensando en alto… :)…

Saludos y gracias
f.

2008/9/30 Fernando G. [email protected]:

  1. si el from es utf-8 (porque lo pone en el string) y el to es utf-8
    porque se lo indico yo… ¿cómo es que se parecen tan poco? (Esto de
    los enconding… digo yo que alguna vez me hará click el cerebro y lo
    entenderé… pero por ahora tengo un líooo)
    Fernando, echale un ojo a esto [1]. A mi me sirvió para entenderlo
    mejor.

[1] The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) – Joel on Software

El día 30 de septiembre de 2008 9:50, Dani D. [email protected]
escribió:> 2008/9/30 Fernando G. [email protected]:

  1. si el from es utf-8 (porque lo pone en el string) y el to es utf-8
    porque se lo indico yo… ¿cómo es que se parecen tan poco? (Esto de
    los enconding… digo yo que alguna vez me hará click el cerebro y lo
    entenderé… pero por ahora tengo un líooo)
    Fernando, echale un ojo a esto [1]. A mi me sirvió para entenderlo mejor.

[1] The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) – Joel on Software

:wink: thx

2008/9/30 Fernando G. [email protected]:

El día 29 de septiembre de 2008 20:24, Daniel R. Troitiño
[email protected] escribió:

No he podido descargar el zip ni ver los enlaces (tengo una conexión a
internet algo limitada),

Qué pasa que los alemanes no tienen buenas ADSLs como nosotros ? :stuck_out_tongue:

Aún no tengo ADSL propio, el que estoy utilizando es un HotSpot Fon,
que amablemente deja acceder a todos los servicios de Google, pero a
nada más (razón para depender más de Google si cabe :). Aunque hoy se
me cae cada dos por tres… debe ser la lluvia.

  • Show quoted text -
    Fijate en los campos que extrae de la expresión regular, primero está
    “before” que se supone que es el texto antes de la parte códificada,
    luego el “from_charset” que es el charset en el que están codificados
    los datos, luego el “quoting_method” que es la forma en la que se
    almacenan los datos (el correo electrónico se supone que solo funciona
    con ASCII 7-bit, todo lo demás son encodings… pero no charset
    encodings), y finalmente el texto “text”.

Tu cadena UTF-8 y su cadena UTF-8 se parecen tan poco porque la suya
está utilizando Base64 (como indican en algunos compañeros por
encima). La “B” entre dos interrogaciones despues del charset es lo
que indica como están codificados los datos del texto.

  1. como sé si el string (en este caso el filename) está codificado? …
    aunque igual no hace falta… le paso el unquoter siempre y a correr:

Por lo que veo pasarle el unquoter debería ser seguro incluso si el
texto no está codificado de maneras “raras”.

Suerte.

El email te dice que es base64 aquí:

Content-Transfer-Encoding: base64

Por lo que simplemente descodificas base 64

irb

require ‘base64’
=> true

Base64.decode_b “=?utf-8?B?SU1HMDAwOTkuanBn?=”
=> “IMG00099.jpg”

Base64.decode_b “hola”
=> “hola”

No se si es eso lo que preguntas.

El día 30 de septiembre de 2008 15:59, Guillermo
[email protected]
escribió:> => “IMG00099.jpg”

Base64.decode_b “hola”
=> “hola”

Sipi… gracias.

Aunque al final he optado por hacerlo con:
TMail::Unquoter.unquote_and_convert_to

Que se encarga de descubrir en que encoding está el string.

Gracias
f.

El día 30 de septiembre de 2008 9:50, Dani D. [email protected]
escribió:> 2008/9/30 Fernando G. [email protected]:

  1. si el from es utf-8 (porque lo pone en el string) y el to es utf-8
    porque se lo indico yo… ¿cómo es que se parecen tan poco? (Esto de
    los enconding… digo yo que alguna vez me hará click el cerebro y lo
    entenderé… pero por ahora tengo un líooo)
    Fernando, echale un ojo a esto [1]. A mi me sirvió para entenderlo mejor.

[1] The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!) – Joel on Software

Guapísimo :slight_smile:

El día 30 de septiembre de 2008 16:23, Daniel R.
Troitiño[email protected]
escribió:> que indica como están codificados los datos del texto.
Osea… que es utf-8 base64… pero que engendro del deminio es este?..
he leído el artículo de encondings que me has pasado (brillante) y
pensé haber entendido que utf8 sólo había uno y ahora veo[1] que hay:

  • UTF-8 quoted printable
  • UTF-8 base64

[1]

  1. como sé si el string (en este caso el filename) está codificado? …
    aunque igual no hace falta… le paso el unquoter siempre y a correr:

Por lo que veo pasarle el unquoter debería ser seguro incluso si el
texto no está codificado de maneras “raras”.

Sip… lo he dejado así: que descodifique siempre.

Suerte.

Gracias :slight_smile:

f.

El día 30 de septiembre de 2008 17:12, Adrián Mugnolo
[email protected]
escribió:> Fernando,

Es que sí son dos codificaciones pero de cosas distintas. Por un
lado, UTF-8 de los caracteres en sí; Base64 y Quoted-printable de
contenido binario de 8 bits en (una representación de) 7 bits.

Aaaaahh! que me saquen de
aquí!
Creo que voy a necesitar un poco de tiempo para ir digiriendo esto :slight_smile:

Gracias.
f.

Fernando,

Es que sí son dos codificaciones pero de cosas distintas. Por un
lado, UTF-8 de los caracteres en sí; Base64 y Quoted-printable de
contenido binario de 8 bits en (una representación de) 7 bits.