Получить позиции байтов для всех частей сообщения MIME - PullRequest
0 голосов
/ 08 апреля 2020

Я пытаюсь получить все байтовые позиции частей MIME электронной почты от Python. Фактически мне нужны диапазоны между границами MIME.

Итак, это очень простое сообщение MIME, скопированное из https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html:

From: Nathaniel Borenstein <nsb@bellcore.com>
To:  Ned Freed <ned@innosoft.com>
Subject: Sample message
MIME-Version: 1.0
Content-type: multipart/mixed; boundary="simple boundary"

This is the preamble.  It is to be ignored, though it
is a handy place for mail composers to include an
explanatory note to non-MIME compliant readers.
--simple boundary

This is implicitly typed plain ASCII text.
It does NOT end with a linebreak.
--simple boundary
Content-type: text/plain; charset=us-ascii

This is explicitly typed plain ASCII text.
It DOES end with a linebreak.

--simple boundary--
This is the epilogue.  It is also to be ignored.

Я хотел бы получить следующие цифры:

  • 351-428 (первая часть с пустыми заголовками)
  • 447-564 (вторая часть с заголовками)

Письма полон наземных мин, поэтому я хочу найти самое надежное решение. Я начал с модуля электронной почты Python и придумал что-то вроде этого:

import email
import email.policy
import mmap

def process_mail(f):
    fp = open(f, 'rb')
    msg = email.message_from_binary_file(fp, policy=email.policy.default)

    boundaries = []
    for part in msg.walk():
        boundary = part.get_boundary()
        if boundary is not None:
            boundaries.append(boundary.encode('utf-8'))
    return boundaries

file = '/tmp/test2'
f = open(file, 'r+b')
mm = mmap.mmap(f.fileno(), 0)
for boundary in process_mail(file):
    pos = 0
    while True:
        idx = mm.find(b'--'+boundary, pos)
        if idx < 0:
            break
        if pos:
            print(pos, idx)
            print("PART", mm[pos:idx])
        pos = idx + len(b'--'+boundary)

, который еще не идеален из-за новых строк (что также может быть проблематичным c, например, \ n или \ r \ n или более странные вещи). Но я чувствую, что это довольно fr agile и хотел бы иметь решение, которое работает правильно во всех случаях (и, возможно, не требует повторного чтения файла один раз для анализа и один раз для нахождения границ).

Вопрос в том, что было бы наиболее эффективным / надежным решением для этого?

...