Проблема с кодировкой в ​​электронных письмах - PullRequest
1 голос
/ 23 декабря 2008

У меня есть небольшой скрипт на python, который извлекает электронные письма с почтового адреса POP и сбрасывает их в файл (один файл - одно электронное письмо)

Затем PHP-скрипт запускает файлы и отображает их.

У меня проблема с электронной почтой в кодировке ISO-8859-1 (Latin-1)

Вот пример текста, который я получаю: =? Iso-8859-1? Q? G = EDsli_Karlsson? = И Sj = E1um hva = F0 = F3li er kl = E1r J

Этот код используется для извлечения писем.

pop = poplib.POP3(server)

mail_list = pop.list()[1]

for m in mail_list:
    mno, size = m.split()
    lines = pop.retr(mno)[1]

    file = StringIO.StringIO("\r\n".join(lines))
    msg = rfc822.Message(file)

    body = file.readlines()

    f = open(str(random.randint(1,100)) + ".email", "w")
    f.write(msg["From"] + "\n")
    f.write(msg["Subject"] + "\n")
    f.write(msg["Date"] + "\n")

    for b in body:
        f.write(b)

Я пробовал, вероятно, все комбинации кодирования / декодирования в python и php.

Ответы [ 5 ]

3 голосов
/ 24 декабря 2008

Вы можете использовать почтовую библиотеку python (python 2.5+), чтобы избежать этих проблем:

import email
import poplib
import random
from cStringIO import StringIO
from email.generator import Generator

pop = poplib.POP3(server)

mail_count = len(pop.list()[1])

for message_num in xrange(mail_count):
    message = "\r\n".join(pop.retr(message_num)[1])
    message = email.message_from_string(message)

    out_file = StringIO()
    message_gen = Generator(out_file, mangle_from_=False, maxheaderlen=60)
    message_gen.flatten(message)
    message_text = out_file.getvalue()

    filename = "%s.email" % random.randint(1,100)
    email_file = open(filename, "w")
    email_file.write(message_text)
    email_file.close()

Этот код получит все сообщения с вашего сервера и превратит их в объекты сообщений Python, а затем снова сведет их в строки для записи в файл. При использовании пакета электронной почты из стандартной библиотеки Python проблемы кодирования и декодирования MIME должны решаться за вас.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я не тестировал этот код, но он должен работать просто отлично.

2 голосов
/ 29 декабря 2008

Есть лучший способ сделать это, но это то, чем я закончил. Спасибо за вашу помощь, ребята.

import poplib, quopri
import random, md5
import sys, rfc822, StringIO
import email
from email.Generator import Generator

user = "email@example.com"
password = "password"
server = "mail.example.com"

# connects
try:
    pop = poplib.POP3(server)
except:
    print "Error connecting to server"
    sys.exit(-1)

# user auth
try:
    print pop.user(user)
    print pop.pass_(password)
except:
    print "Authentication error"
    sys.exit(-2)

# gets the mail list
mail_list = pop.list()[1]

for m in mail_list:
    mno, size = m.split()
    message = "\r\n".join(pop.retr(mno)[1])
    message = email.message_from_string(message)

    # uses the email flatten
    out_file = StringIO.StringIO()
    message_gen = Generator(out_file, mangle_from_=False, maxheaderlen=60)
    message_gen.flatten(message)
    message_text = out_file.getvalue()

    # fixes mime encoding issues (for display within html)
    clean_text = quopri.decodestring(message_text)

    msg = email.message_from_string(clean_text)

    # finds the last body (when in mime multipart, html is the last one)
    for part in msg.walk():
        if part.get_content_type():
            body = part.get_payload(decode=True)

    filename = "%s.email" % random.randint(1,100)

    email_file = open(filename, "w")

    email_file.write(msg["From"] + "\n")
    email_file.write(msg["Return-Path"] + "\n")
    email_file.write(msg["Subject"] + "\n")
    email_file.write(msg["Date"] + "\n")
    email_file.write(body)

    email_file.close()

pop.quit()
sys.exit()
2 голосов
/ 24 декабря 2008

Это MIME-кодировка заголовков, RFC 2047 . Вот как расшифровать его в Python:

import email.Header
import sys

header_and_encoding = email.Header.decode_header(sys.stdin.readline())
for part in header_and_encoding:
    if part[1] is None:
        print part[0],
    else:
        upart = (part[0]).decode(part[1])
        print upart.encode('latin-1'),
print

Более подробные объяснения (на французском языке) в http://www.bortzmeyer.org/decoder-en-tetes-courrier.html

1 голос
/ 23 декабря 2008

До недавнего времени обычные Latin-N или utf-N не допускались в заголовках, что означает, что они будут кодироваться с помощью метода, описанного вначале в RFC-1522 , но они были заменены потом. Ударения кодируются либо в цитируемой печати, либо в Base64, и это обозначается? Q? (или «B» для Base64). Вам придется их расшифровать. Ох, и пространство закодировано как "_". См. Википедия .

0 голосов
/ 23 декабря 2008

Это MIME-контент, и именно так на самом деле выглядит электронная почта, а не ошибка где-то. Вы должны использовать библиотеку декодирования MIME (или самостоятельно ее декодировать) на стороне PHP (которая, если я правильно понял, является той, которая действует как средство рендеринга электронной почты).

В Python вы бы использовали mimetools . В PHP я не уверен. Похоже, что в Zend-фреймворке где-то есть MIME-парсер, и, вероятно, вокруг плавают миллионы фрагментов.

http://en.wikipedia.org/wiki/MIME#Encoded-Word

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...