email.generator: تولید اسناد MIME

کد منبع: Lib/email/generator.py


یکی از رایج‌ترین وظایف، تولید نسخه‌ی تخت (سریال‌شده) پیام ایمیلی است که توسط یک ساختار شیء پیام نمایش داده می‌شود. اگر بخواهید پیام خود را از طریق smtplib.SMTP.sendmail() ارسال کنید، یا پیام را در کنسول چاپ کنید، باید این کار را انجام دهید. دریافت یک ساختار شیء پیام و تولید یک بازنمایی سریال‌شده، وظیفه‌ی کلاس‌های تولیدگر است.

مانند ماژول email.parser، شما محدود به کارکرد تولیدگر همراه نیستید؛ می‌توانید خودتان یکی را از صفر بنویسید. با این حال، تولیدگر همراه می‌داند چگونه بیشتر پیام‌های ایمیل را به‌صورت سازگار با استانداردها تولید کند، باید پیام‌های ایمیل MIME و غیر MIME را به‌خوبی مدیریت کند، و به‌گونه‌ای طراحی شده است که عملیات تجزیه و تولید مبتنی بر بایت معکوس یکدیگر باشند، به‌شرط آنکه برای هر دو از همان سیاست بدون تبدیل policy استفاده شود. یعنی تجزیه‌ی جریان بایت سریال‌شده از طریق کلاس BytesParser و سپس تولید مجدد جریان بایت سریال‌شده با استفاده از BytesGenerator باید خروجی‌ای کاملاً یکسان با ورودی تولید کند [1]. (از سوی دیگر، استفاده از تولیدگر روی یک EmailMessage که به‌صورت برنامه‌ای ساخته شده است ممکن است باعث ایجاد تغییراتی در شیء EmailMessage شود، زیرا مقادیر پیش‌فرض پر می‌شوند.)

می‌توان از کلاس Generator برای تبدیل یک پیام به یک نمایش سریال‌سازی‌شده‌ی متنی (در مقابل دودویی) استفاده کرد، اما از آن‌جا که یونیکد نمی‌تواند داده‌های دودویی را مستقیماً بازنمایی کند، پیام ناگزیر با استفاده از روش‌های استاندارد RFC ایمیل برای کدگذاری انتقال محتوا (Content Transfer Encoding) جهت کدگذاری پیام‌های ایمیل برای انتقال بر روی کانال‌هایی که «8 bit clean» نیستند، به چیزی تبدیل می‌شود که فقط شامل نویسه‌های ASCII باشد.

برای پشتیبانی از پردازش بازتولیدپذیر پیام‌های امضاشده با SMIME، Generator شکستن سرآیند (header folding) را برای بخش‌های پیام از نوع multipart/signed و همه زیربخش‌ها غیرفعال می‌کند.

class email.generator.BytesGenerator(outfp, mangle_from_=None, maxheaderlen=None, *, policy=None)

یک شیء BytesGenerator برمی‌گرداند که هر پیام ارائه‌شده به متد flatten()، یا هر متن کدگذاری‌شده با surrogateescape ارائه‌شده به متد write() را در file-like object outfp می‌نویسد. outfp باید از یک متد write پشتیبانی کند که داده‌های دودویی را می‌پذیرد.

اگر mangle_from_ اختیاری True باشد، یک نویسه > در ابتدای هر خط از بدنه که با رشته دقیق "From " شروع می‌شود، قرار می‌گیرد، یعنی From و به‌دنبال آن یک فاصله در ابتدای خط. مقدار پیش‌فرض mangle_from_ برابر با مقدار تنظیم mangle_from_ در policy است (که برای سیاست compat32 برابر True و برای همه سیاست‌های دیگر False است). mangle_from_ برای استفاده در مواردی در نظر گرفته شده است که پیام‌ها در قالب mbox یونیکس ذخیره می‌شوند (ببینید mailbox و WHY THE CONTENT-LENGTH FORMAT IS BAD).

اگر maxheaderlen برابر None نباشد، هر خط سرآیند‌ای که طولانی‌تر از maxheaderlen باشد دوباره تا زده می‌شود، یا اگر 0 باشد، هیچ سرآیند‌ای دوباره پیچیده نمی‌شود. اگر manheaderlen برابر None باشد (پیش‌فرض)، سرآیند‌ها و سایر سطرهای پیام طبق تنظیمات policy پیچیده می‌شوند.

اگر policy مشخص شده باشد، از آن سیاست برای کنترل تولید پیام استفاده می‌شود. اگر policy برابر None باشد (پیش‌فرض)، از سیاست مرتبط با شیء Message یا EmailMessage ارسال‌شده به flatten برای کنترل تولید پیام استفاده می‌شود. برای جزئیات درباره اینکه policy چه چیزی را کنترل می‌کند، email.policy را ببینید.

اضافه شده در نسخه‌ی 3.2.

تغییر یافته در نسخه‌ی 3.3: کلیدواژه‌ی policy افزوده شد.

تغییر یافته در نسخه‌ی 3.6: رفتار پیش‌فرض پارامترهای mangle_from_ و maxheaderlen پیروی از سیاست است.

flatten(msg, unixfrom=False, linesep=None)

نمایش متنی ساختار شیء پیام ریشه‌گرفته از msg را در پرونده خروجی مشخص‌شده هنگام ایجاد نمونه BytesGenerator چاپ می‌کند.

اگر گزینه‌ی policy یعنی cte_type برابر 8bit باشد (پیش‌فرض)، تمام سرآیندهای موجود در پیام اصلی تجزیه‌شده که تغییر نکرده‌اند، به خروجی کپی می‌شوند، به‌گونه‌ای که بایت‌هایی که بیت بالایی آن‌ها تنظیم‌شده است، همان‌طور که در پیام اصلی بوده‌اند بازتولید شوند، و Content-Transfer-Encoding غیر ASCII هر بخش بدنه‌ای که دارای آن است حفظ می‌شود. اگر cte_type برابر 7bit باشد، بایت‌هایی که بیت بالایی آن‌ها تنظیم‌شده است، در صورت نیاز با استفاده از یک Content-Transfer-Encoding سازگار با ASCII تبدیل می‌شوند. یعنی بخش‌هایی که Content-Transfer-Encoding غیر ASCII دارند (Content-Transfer-Encoding: 8bit)، به یک Content-Transfer-Encoding سازگار با ASCII تبدیل می‌شوند، و بایت‌های غیر ASCII نامعتبر از نظر RFC در سرآیندها، با استفاده از مجموعه‌نویسه‌ی unknown-8bit در MIME کدگذاری می‌شوند، و بدین ترتیب، آن‌ها را با RFC سازگار می‌کند.

اگر unixfrom برابر True باشد، جداکننده‌ی سرآیند پاکت (envelope header delimiter) که در قالب صندوق پستی یونیکس استفاده می‌شود (به mailbox مراجعه کنید) پیش از نخستین سرآیند از سرآیندهای RFC 5322 شیء پیام ریشه درج می‌شود. اگر شیء ریشه سرآیند پاکت نداشته باشد، یک سرآیند پاکت استاندارد ایجاد می‌شود. مقدار پیش‌فرض False است. توجه داشته باشید که برای زیربخش‌ها، هرگز هیچ سرآیند پاکتی درج نمی‌شود.

اگر linesep None نباشد، از آن به‌عنوان نویسه جداکننده میان تمام سطرهای پیام مسطح‌شده استفاده می‌شود. اگر linesep None باشد (پیش‌فرض)، از مقدار تعیین‌شده در policy استفاده می‌شود.

clone(fp)

یک رونوشت (clone) مستقل از این نمونه‌ی BytesGenerator با دقیقاً همان تنظیمات گزینه‌ها، و با fp به‌عنوان outfp جدید برمی‌گرداند.

write(s)

s را با کدک ASCII و هندلر خطای surrogateescape کدگذاری کنید و آن را به متد write از outfp که به سازنده‌ی BytesGenerator ارسال شده است، بفرستید.

برای سهولت، EmailMessage متدهای as_bytes() و bytes(aMessage) (که به __bytes__() نیز شناخته می‌شود) را فراهم می‌کند، که تولید یک نمایش دودویی سریال‌شده از یک شیء پیام را ساده می‌کنند. برای جزئیات بیشتر، email.message را ببینید.

از آن‌جا که رشته‌ها نمی‌توانند داده‌های دودویی را نشان دهند، کلاس Generator باید هرگونه داده‌ی دودویی موجود در هر پیامی را که به‌صورت مسطح درمی‌آورد، با تبدیل آن به یک Content-Transfer_Encoding سازگار با ASCII، به قالبی سازگار با ASCII تبدیل کند. با استفاده از اصطلاحات RFCهای ایمیل، می‌توانید این‌طور تصور کنید که Generator در حال سریال‌سازی به یک جریان ورودی/خروجی است که «8 bit clean» نیست. به بیان دیگر، بیشتر برنامه‌ها خواهند خواست از BytesGenerator استفاده کنند، نه Generator.

class email.generator.Generator(outfp, mangle_from_=None, maxheaderlen=None, *, policy=None)

یک شیء Generator بازگشت می‌دهد که هر پیام ارائه‌شده به متد flatten()، یا هر متن ارائه‌شده به متد write() را در file-like object outfp می‌نویسد. outfp باید از یک متد write پشتیبانی کند که داده‌های رشته‌ای را می‌پذیرد.

اگر mangle_from_ اختیاری True باشد، یک نویسه > در ابتدای هر خط از بدنه که با رشته دقیق "From " شروع می‌شود، قرار می‌گیرد، یعنی From و به‌دنبال آن یک فاصله در ابتدای خط. مقدار پیش‌فرض mangle_from_ برابر با مقدار تنظیم mangle_from_ در policy است (که برای سیاست compat32 برابر True و برای همه سیاست‌های دیگر False است). mangle_from_ برای استفاده در مواردی در نظر گرفته شده است که پیام‌ها در قالب mbox یونیکس ذخیره می‌شوند (ببینید mailbox و WHY THE CONTENT-LENGTH FORMAT IS BAD).

اگر maxheaderlen برابر None نباشد، هر خط سرآیند‌ای که طولانی‌تر از maxheaderlen باشد دوباره تا زده می‌شود، یا اگر 0 باشد، هیچ سرآیند‌ای دوباره پیچیده نمی‌شود. اگر manheaderlen برابر None باشد (پیش‌فرض)، سرآیند‌ها و سایر سطرهای پیام طبق تنظیمات policy پیچیده می‌شوند.

اگر policy مشخص شده باشد، از آن سیاست برای کنترل تولید پیام استفاده می‌شود. اگر policy برابر None باشد (پیش‌فرض)، از سیاست مرتبط با شیء Message یا EmailMessage ارسال‌شده به flatten برای کنترل تولید پیام استفاده می‌شود. برای جزئیات درباره اینکه policy چه چیزی را کنترل می‌کند، email.policy را ببینید.

تغییر یافته در نسخه‌ی 3.3: کلیدواژه‌ی policy افزوده شد.

تغییر یافته در نسخه‌ی 3.6: رفتار پیش‌فرض پارامترهای mangle_from_ و maxheaderlen پیروی از سیاست است.

flatten(msg, unixfrom=False, linesep=None)

نمایش متنی ساختار شیء پیام که ریشه در msg دارد را به پرونده خروجی مشخص‌شده در زمان ایجاد نمونه‌ی Generator چاپ می‌کند.

اگر گزینه‌ی cte_type در policy برابر 8bit باشد، پیام به‌گونه‌ای تولید می‌شود که گویی این گزینه روی 7bit تنظیم شده است. (این کار لازم است، زیرا رشته‌ها نمی‌توانند بایت‌های غیرASCII را بازنمایی کنند.) بایت‌هایی که بیت پرارزش آن‌ها ۱ است، در صورت لزوم با استفاده از یک Content-Transfer-Encoding سازگار با ASCII تبدیل می‌شوند. یعنی بخش‌هایی که Content-Transfer-Encoding غیرASCII دارند (Content-Transfer-Encoding: 8bit) به یک Content-Transfer-Encoding سازگار با ASCII تبدیل می‌شوند و بایت‌های غیرASCII نامعتبر از نظر RFC در سرآیند‌ها با استفاده از مجموعه نویسه‌ی unknown-8bit در MIME کدگذاری می‌شوند، تا بدین ترتیب آن‌ها مطابق RFC شوند.

اگر unixfrom برابر True باشد، جداکننده‌ی سرآیند پاکت (envelope header delimiter) که در قالب صندوق پستی یونیکس استفاده می‌شود (به mailbox مراجعه کنید) پیش از نخستین سرآیند از سرآیندهای RFC 5322 شیء پیام ریشه درج می‌شود. اگر شیء ریشه سرآیند پاکت نداشته باشد، یک سرآیند پاکت استاندارد ایجاد می‌شود. مقدار پیش‌فرض False است. توجه داشته باشید که برای زیربخش‌ها، هرگز هیچ سرآیند پاکتی درج نمی‌شود.

اگر linesep None نباشد، از آن به‌عنوان نویسه جداکننده میان تمام سطرهای پیام مسطح‌شده استفاده می‌شود. اگر linesep None باشد (پیش‌فرض)، از مقدار تعیین‌شده در policy استفاده می‌شود.

تغییر یافته در نسخه‌ی 3.2: پشتیبانی از کدگذاری مجدد بدنه‌های پیام 8bit و آرگومان linesep افزوده شد.

clone(fp)

یک نسخه‌ی رونوشت (clone) از این نمونه‌ی Generator با دقیقاً همان گزینه‌ها و با fp به‌عنوان outfp جدید برمی‌گرداند.

write(s)

s را با استفاده از متد write از outfp که به سازنده‌ی Generator داده شده است، می‌نویسد. این کار API شبه‌پرونده کافی را برای استفاده از نمونه‌های Generator در تابع print() فراهم می‌کند.

برای سهولت، EmailMessage متدهای as_string() و str(aMessage) (یا همان __str__()) را فراهم می‌کند، که تولید یک نمایش رشته‌ای قالب‌بندی‌شده از یک شیء پیام را ساده می‌کنند. برای جزئیات بیشتر، email.message را ببینید.

ماژول email.generator همچنین یک کلاس مشتق، DecodedGenerator، ارائه می‌کند که مانند کلاس پایه‌ی Generator است، با این تفاوت که بخش‌های غیر text سریال‌سازی نمی‌شوند، بلکه در جریان خروجی به‌وسیله‌ی رشته‌ای نمایش داده می‌شوند که حاصل از الگویی است که با اطلاعات مربوط به آن بخش پر شده است.

class email.generator.DecodedGenerator(outfp, mangle_from_=None, maxheaderlen=None, fmt=None, *, policy=None)

مانند Generator عمل می‌کند، با این تفاوت که برای هر زیربخشی از پیامی که به Generator.flatten() داده می‌شود، اگر زیربخش از نوع اصلی text باشد، بار کدگشایی‌شده‌ی آن زیربخش را چاپ می‌کند، و اگر نوع اصلی text نباشد، به‌جای چاپ آن، رشته fmt را با استفاده از اطلاعات آن بخش تکمیل می‌کند و رشته‌ی تکمیل‌شده‌ی حاصل را چاپ می‌کند.

برای پر کردن fmt، دستور fmt % part_info را اجرا کنید، که در آن part_info یک دیکشنری متشکل از کلیدها و مقدارهای زیر است:

  • type -- نوع MIME کاملِ بخش غیرِ text

  • maintype -- نوع MIME اصلیِ بخش غیرِ text

  • subtype -- زیرنوع MIME برای بخش غیر text

  • filename -- نام پرونده بخش غیر text

  • description -- توضیح مرتبط با بخش غیرtext

  • encoding -- کدگذاری انتقال محتوا برای بخش غیر text

اگر fmt برابر None باشد، از fmt پیش‌فرض زیر استفاده کنید:

[بخش غیرمتنی (%(type)s) پیام حذف شد، نام پرونده %(filename)s]

آرگومان‌های اختیاری _mangle_from_ و maxheaderlen همانند کلاس پایه‌ی Generator هستند.

پانویس‌ها