[Risolto][Python3][sendmail] encoding/decoding di email

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

[Risolto][Python3][sendmail] encoding/decoding di email

Messaggio da rai »

Un saluto a tutti.

Uno script (peraltro funzionante senza errori) invia una mail e *alcuni* destinatari non ne leggono i caratteri nonASCII. Per dire: gli stessi caratteri diventano leggibili se quel destinatario inoltra quella stessa mail su Gmail.
La stringa che costituisce il corpo della mail viene estratta da un file di appoggio creato localmente. Questa è la mia localizzazione

Codice: Seleziona tutto

$ locale
LANG=it_IT.UTF-8
LANGUAGE=it:fr:en
LC_CTYPE="it_IT.UTF-8"
LC_NUMERIC=it_IT.UTF-8
LC_TIME=it_IT.UTF-8
LC_COLLATE="it_IT.UTF-8"
LC_MONETARY=it_IT.UTF-8
LC_MESSAGES="it_IT.UTF-8"
LC_PAPER=it_IT.UTF-8
LC_NAME=it_IT.UTF-8
LC_ADDRESS=it_IT.UTF-8
LC_TELEPHONE=it_IT.UTF-8
LC_MEASUREMENT=it_IT.UTF-8
LC_IDENTIFICATION=it_IT.UTF-8
LC_ALL=
Penso che sia un problema mio e non (solo) dei destinatari perché se eseguo l' invio con uno script bash, a partire dallo stesso file di testo, i caratteri si leggono tutti, e anche sui destinatari `problematici'. Quindi deve esserci un modo per evitare questo fastidio ma non mi raccapezzo.

posto il frammento che ritengo utile, sfoltito dagli import e da tutti i controlli di errori ed eccezioni

Codice: Seleziona tutto

[ . . . ]
ilTXT = "/tmp/{}.txt".format(CognomeNome) # il file di testo (creato con libreoffice)
with open(ilTXT, "r") as f:
    testo = f.read()
for regex in LISTAREGEX:
    match = re.search(regex, testo, re.DOTALL)
    if 'oggetto1' in regex:
        SUBJECT = match.group(0).strip()
    elif 'contatti' in regex:
        TO = match.group(0).strip()
    elif 'messaggio1' in regex:
        BODY = match.group(0).strip()

#
#   costruisce le mail   #
#¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
message = """\
From: {}
To: {}
Subject: {}

{}
""".format(USER, TO, SUBJECT, BODY)

#
#   invia le mail   #
#¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
listaDestinatari = TO.split(',')

s = smtplib.SMTP_SSL(smtpSERVER)invio
s.login(USER, password)
s.sendmail(USER, listaDestinatari, message.encode('utf-8')) # <------- ecco il punto
s.quit
[ . . . ]
ma se servisse posto tutto il malloppo, l'ho sfoltito sperando di invogliare di più alla lettura i volenterosi
Grazie
Ultima modifica di rai il giovedì 23 marzo 2017, 16:07, modificato 1 volta in totale.
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: [Python3] encoding/decoding di caratteri

Messaggio da crap0101 »

ipotizzo che il problema sia appunto la codifica in utf-8... certi "visualizzatori" probabilmente sono abbastanza "furbi" da riconoscere che non è testo ascii e quindi lo decodificano correttamente, mentre altri non lo fanno e - in mancanza di specifiche - lo trattano come "plain text".
btw, nella doc del metodo sendmail() si dice appunto che il parametro "msg" dev'essere:
msg may be a string containing characters in the ASCII range, or a byte string
per cui è possibile che testo codificato diversamente dia problemi.

In un prog che mi pare ti avevo già linkato avevo fato diversamente, creando una classe per i messaggi esclusivamente in ascii e altre per quelli più "complessi", di cui ti riporto un estratto:

Codice: Seleziona tutto

class PlainMsg(MailMessage):
    """Plain text mail object."""
    def __init__(self, sender, receiver, subject, text):
        super(PlainMsg, self).__init__(
            sender, receiver, subject, text, None);

    def get_message(self, receiver=None):
        receiver = receiver if receiver is not None else self.receiver
        _time = mmutils.mail_format_time()
        return ("From: %s\r\nTo: %s\r\nSubject: %s\r\n"
                "Date: %s\r\nX-Mailer: %s\r\n\r\n%s"
                % (self.sender, receiver, self.subject,
                   _time, self.xmailer, self.text))

class MimeMsg(MailMessage):
    """Plain text mail object."""
    def __init__(self, sender, receiver, subject, text, ttype, attachments):
        super(MimeMsg, self).__init__(
            sender, receiver, subject, text, attachments)
        self.text_type = ttype
        self.build()

    def build(self):
        if not self.attachments:
            if self.text_type == 'html':
                self.msg = MIMENonMultipart('text', 'html')
            else:
                self.msg = MIMENonMultipart('text', 'plain', charset='utf-8')
            self.msg.set_payload(self.text)
            self.msg['boundary'] = self.delimiter
        else:
            self.msg = MIMEMultipart(boundary=self.delimiter)
            if self.text_type == 'html':
                self.msg.attach(MIMEText(self.text, 'html'))
            else:

in cui come vedi uso il modulo email.mime che semplifica un po' le cose... e che vedo nella stdlib di py3 è stato almeno in parte sostituito da email.contentmanager
http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: [Python3] encoding/decoding di caratteri

Messaggio da rai »

Grazie crap0101, ho fatto tesoro del programma che hai condiviso in questa discussione, tra l'altro anche applicando la classe email.mime.text.MIMEText() che determina Content-Type e charset in modo trasparente all'utente.
Ma l'ho usata solo per costruire mail con allegati. Per mail non-multipart mi era sembrato overkill usare il modulo email per costruire il messaggio e invece ...

Comunque la doc di sendmail, che tu citi, mi sembra migliorabile: dice di fornire il msg come bytes, che è appunto quello che fa il mio script, ma non avvisa ( se non fra le righe ) della possibile mis-decodifica da parte dei destinatari.
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: [Python3] encoding/decoding di caratteri

Messaggio da crap0101 »

uhm... nel codice che hai postato non mi pare che il messaggio sia un oggetto di tipo bytes, anche perchè ti darebbe errore quando utilizzi il metodo encode() che gli oggetti bytes non hanno.
http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: [Python3] encoding/decoding di caratteri

Messaggio da rai »

Sì `message' è sicuramente str (essendo somma di stringhe matchate con re).
Ma quando la prende sendmail dovrebbe essere diventata bytes dato che la passo come `message.encode() '
O almeno, salvo errori

Codice: Seleziona tutto

>>> type(stringa)
<class 'str'>
>>> type(stringa.encode())
<class 'bytes'>
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: [Python3] encoding/decoding di caratteri

Messaggio da crap0101 »

sì giusto, quindi dev'essere proprio come dice la doc e - che sia stringa o che siano bytes - la codifica dev'essere ascii.
Credo quindi non ci sia molto da fare mandano la mail in quella modalità senza usare i mime con cui si può specificare la codifica che verrà poi letta dal prog destinatario.
http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2842
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: [Python3] encoding/decoding di caratteri

Messaggio da rai »

Sì quindi faccio una cosa del genere:

Codice: Seleziona tutto

import smtplib
from email.mime.nonmultipart import MIMENonMultipart

SUBJECT = "prova"
FROM = user
PASSWORD = password
TO = ['destinatario1@mail.com', 'destinatario2@mail.it']
TEXT = " à € ì ò ù "
msg = MIMENonMultipart('text', 'plain', charset='utf-8')
msg['Subject'] = SUBJECT
msg['From'] = FROM
msg['To'] = ", ".join(TO)
msg.set_payload(TEXT + ' Creata col modulo email.mime.')

SERVER = "il.server.smtps"
smtp = smtplib.SMTP_SSL(SERVER)
smtp.login(FROM, PASSWORD)
smtp.sendmail(FROM, TO, msg.as_string().encode('utf-8'))
smtp.quit()
il che funziona comunque, anche se la mail è 100% ascii

Grazie, come sempre
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 6 ospiti