email.headerregistry: اشیاء سرآیند سفارشی

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


اضافه شده در نسخه‌ی 3.6: [1]

سرآیندها با زیرکلاس‌های سفارشی از str نمایش داده می‌شوند. کلاس خاصی که برای نمایش یک سرآیند مشخص به کار می‌رود، توسط header_factory از policy که در زمان ایجاد سرآیندها معتبر است، تعیین می‌شود. این بخش header_factory خاصی را مستند می‌کند که توسط بسته email برای مدیریت پیام‌های ایمیل منطبق با RFC 5322 پیاده‌سازی شده است و نه‌تنها اشیای سرآیند سفارشی برای انواع مختلف سرآیند فراهم می‌کند، بلکه سازوکار توسعه‌ای برای برنامه‌ها فراهم می‌کند تا انواع سرآیند سفارشی خود را اضافه کنند.

هنگام استفاده از هر یک از اشیاء سیاست مشتق‌شده از EmailPolicy، تمام سرآیندها توسط HeaderRegistry تولید می‌شوند و BaseHeader را به‌عنوان آخرین کلاس پایه خود دارند. هر کلاس سرآیند یک کلاس پایه اضافی دارد که بر اساس نوع سرآیند تعیین می‌شود. برای مثال، بسیاری از سرآیندها کلاس UnstructuredHeader را به‌عنوان کلاس پایه دیگر خود دارند. کلاس دوم تخصصی برای یک سرآیند، با استفاده از جدول جستجویی که در HeaderRegistry ذخیره‌شده است، بر اساس نام سرآیند تعیین می‌شود. همه این موارد برای برنامه کاربردی معمول به‌صورت شفاف مدیریت می‌شوند، اما رابط‌هایی برای تغییر رفتار پیش‌فرض جهت استفاده در برنامه‌های پیچیده‌تر فراهم شده‌اند.

بخش‌های زیر ابتدا کلاس‌های پایه‌ی سرآیند و ویژگی‌های آن‌ها را مستند می‌کنند، سپس به API برای تغییر رفتار HeaderRegistry می‌پردازند، و در نهایت کلاس‌های پشتیبانی مورد استفاده برای بازنمایی داده‌های تجزیه‌شده از سرآیند‌های ساختاریافته را پوشش می‌دهند.

class email.headerregistry.BaseHeader(name, value)

name and value are passed to BaseHeader from the header_factory call. The string value of any header object is the value fully decoded to a string.

این کلاس پایه، ویژگی‌های فقط‌خواندنی زیر را تعریف می‌کند:

name

نام سرآیند (بخش فیلد پیش از ':'). این دقیقاً همان مقداری است که به‌عنوان name در فراخوانی header_factory ارسال شده است؛ یعنی بزرگی و کوچکی حروف حفظ می‌شود.

defects

یک تاپل از نمونه‌های HeaderDefect که هر مشکل انطباق با RFC را که در حین تجزیه یافت می‌شود، گزارش می‌کنند. بسته‌ی email تلاش می‌کند در تشخیص مسائل انطباق کامل باشد. برای بحثی در مورد انواع نقص‌هایی که ممکن است گزارش شوند، ماژول errors را ببینید.

max_count

حداکثر تعداد سرآیندهای این نوع که می‌توانند name یکسانی داشته باشند. مقدار None به معنای نامحدود است. مقدار این ویژگی در BaseHeader برابر None است؛ انتظار می‌رود کلاس‌های سرآیند تخصصی این مقدار را در صورت نیاز بازنویسی کنند.

BaseHeader همچنین متد زیر را ارائه می‌دهد، که توسط کد کتابخانه ایمیل فراخوانی می‌شود و به‌طور کلی نباید توسط برنامه‌های کاربردی فراخوانی شود:

fold(*, policy)

رشته‌ای حاوی نویسه‌های linesep به‌میزان لازم برای تا کردن صحیح سرآیند مطابق policy برمی‌گرداند. cte_type با مقدار 8bit به‌صورت 7bit در نظر گرفته می‌شود، زیرا سرآیندها نمی‌توانند حاوی داده‌های دودویی دلخواه باشند. اگر utf8 برابر False باشد، داده‌های غیر ASCII طبق RFC 2047 کدگذاری می‌شوند.

BaseHeader به‌تنهایی نمی‌تواند برای ایجاد یک شیء سرآیند به کار رود. این کلاس پروتکلی را تعریف می‌کند که هر سرآیند تخصصی برای ایجاد شیء سرآیند با آن همکاری می‌کند. به‌طور مشخص، BaseHeader الزام می‌کند که کلاس تخصصی یک classmethod() به نام parse فراهم کند. این متد به‌صورت زیر فراخوانی می‌شود:

parse(string, kwds)

kwds is a dictionary containing one pre-initialized key, defects. defects is an empty list. The parse method should append any detected defects to this list. On return, the kwds dictionary must contain values for at least the keys decoded, defects and parse_tree. decoded should be the string value for the header (that is, the header value fully decoded to a string). parse_tree is set to the parse tree obtained from parsing the header. The parse method should assume that string may contain content-transfer-encoded parts, but should correctly handle all valid Unicode characters as well so that it can parse un-encoded header values.

سپس __new__BaseHeader نمونه‌ی سرآیند را ایجاد می‌کند و متد init آن را فراخوانی می‌کند. کلاس تخصصی تنها در صورتی لازم است یک متد init ارائه کند که بخواهد ویژگی‌های اضافی، فراتر از آنچه خود BaseHeader فراهم می‌کند، تنظیم کند. چنین متد init باید به این صورت باشد:

def init(self, /, *args, **kw):
    self._myattr = kw.pop('myattr')
    super().init(*args, **kw)

یعنی هر چیز اضافی که کلاس تخصصی در دیکشنری kwds قرار می‌دهد باید حذف و مدیریت شود، و محتوای باقی‌مانده‌ی kwargs) به متد init از BaseHeader ارسال شود.

class email.headerregistry.UnstructuredHeader

یک سرآیند «بدون ساختار»، نوع پیش‌فرض سرآیند در RFC 5322 است. هر سرآیندی که سینتکس مشخصی نداشته باشد، بدون ساختار تلقی می‌شود. یک نمونه کلاسیک از سرآیند بدون ساختار، سرآیند Subject است.

In RFC 5322, an unstructured header is a run of arbitrary text in the ASCII character set. RFC 2047, however, has an RFC 5322 compatible mechanism for encoding non-ASCII text as ASCII characters within a header value. When a value containing encoded words is passed to the constructor, the UnstructuredHeader parser converts such encoded words into a string, following the RFC 2047 rules for unstructured text. The parser uses heuristics to attempt to decode certain non-compliant encoded words. Defects are registered in such cases, as well as defects for issues such as invalid characters within the encoded words or the non-encoded text.

این نوع سرآیند، هیچ ویژگی اضافه‌ای ارائه نمی‌دهد.

class email.headerregistry.DateHeader

RFC 5322 قالب بسیار مشخصی را برای تاریخ‌ها در سرآیندهای ایمیل تعیین می‌کند. پارسر DateHeader آن قالب تاریخ و همچنین تعدادی از صورت‌های متفاوت را که گاهی «در عمل» یافت می‌شوند، تشخیص می‌دهد.

این نوع سرآیند، ویژگی‌های اضافی زیر را فراهم می‌کند:

datetime

اگر مقدار سرآیند بتواند به‌عنوان یک تاریخ معتبر در یکی از قالب‌ها تشخیص داده شود، این ویژگی شامل یک نمونه datetime خواهد بود که نشان‌دهنده آن تاریخ است. اگر منطقه زمانی تاریخ ورودی به‌صورت -0000 مشخص شده باشد (که نشان می‌دهد در UTC است اما حاوی اطلاعاتی درباره منطقه زمانی منبع نیست)، آنگاه datetime یک datetime ساده خواهد بود. اگر یک آفست منطقه زمانی مشخص یافت شود (از جمله +0000)، آنگاه datetime شامل یک datetime آگاه خواهد بود که از datetime.timezone برای ثبت آفست منطقه زمانی استفاده می‌کند.

مقدار decoded سرآیند با قالب‌بندی datetime مطابق قواعد RFC 5322 تعیین می‌شود؛ یعنی، به‌صورت زیر تنظیم می‌شود:

email.utils.format_datetime(self.datetime)

هنگام ایجاد یک DateHeader، value می‌تواند نمونه‌ای از datetime باشد. این بدان معناست که، برای مثال، کد زیر معتبر است و همان کاری را که انتظار می‌رود انجام می‌دهد:

msg['Date'] = datetime(2011, 7, 15, 21)

از آن‌جا که این یک datetime ساده (naive) است، به‌عنوان یک مهر زمانی UTC تفسیر می‌شود و مقدار حاصل دارای منطقه زمانی -0000 خواهد بود. بسیار مفیدتر آن است که از تابع localtime() در ماژول utils استفاده کنید:

msg['Date'] = utils.localtime()

این مثال سرآیند تاریخ را با استفاده از آفست منطقه‌ی زمانی (timezone offset) فعلی، روی زمان و تاریخ فعلی تنظیم می‌کند.

class email.headerregistry.AddressHeader

سرآیندهای نشانی یکی از پیچیده‌ترین انواع سرآیندهای ساختاریافته هستند. کلاس AddressHeader یک رابط عام برای هر سرآیند نشانی ارائه می‌دهد.

این نوع سرآیند، ویژگی‌های اضافی زیر را فراهم می‌کند:

groups

یک تاپل از اشیای Group که نشانی‌ها و گروه‌های یافت‌شده در مقدار سرآیند را کدگذاری می‌کنند. نشانی‌هایی که بخشی از یک گروه نیستند، در این فهرست به‌صورت Groupsهای تک‌نشانی بازنمایی می‌شوند که display_name آن‌ها None است.

addresses

تاپلی از اشیای Address که همه‌ی نشانی‌های منفردِ موجود در مقدار سرایند را کدگذاری می‌کنند. اگر مقدار سرایند شامل گروهی باشد، نشانی‌های منفردِ آن گروه در نقطه‌ای که گروه در مقدار ظاهر می‌شود، در فهرست گنجانده می‌شوند (یعنی فهرست نشانی‌ها به یک فهرست یک‌بعدی «تخت‌شده» تبدیل می‌شود).

The decoded value of the header will have all encoded words decoded to a string. idna encoded domain names are also decoded to a string. The decoded value is set by joining the str value of the elements of the groups attribute with ', '.

می‌توان از فهرستی از اشیاء Address و Group در هر ترکیبی برای تنظیم مقدار یک سرآیند نشانی استفاده کرد. اشیاء Group که display_name آن‌ها None است، به‌عنوان نشانی‌های منفرد تعبیر می‌شوند؛ این امر امکان می‌دهد یک فهرست نشانی با حفظ گروه‌ها، با استفاده از فهرستی که از ویژگی groups سرآیند مبدأ به دست می‌آید، کپی شود.

class email.headerregistry.SingleAddressHeader

زیرکلاسی از AddressHeader که یک ویژگی اضافی می‌افزاید:

address

تنها نشانی کدگذاری‌شده توسط مقدار سرآیند. اگر مقدار سرآیند در واقع شامل بیش از یک نشانی باشد (که تحت policy پیش‌فرض، نقض RFC خواهد بود)، دسترسی به این ویژگی منجر به ValueError خواهد شد.

بسیاری از کلاس‌های فوق همچنین دارای یک گونه‌ی Unique هستند (برای مثال، UniqueUnstructuredHeader). تنها تفاوت این است که در گونه‌ی Unique، max_count روی ۱ تنظیم شده است.

class email.headerregistry.MIMEVersionHeader

در واقع تنها یک مقدار معتبر برای سرآیند MIME-Version وجود دارد، و آن 1.0 است. برای سازگاری با آینده، این کلاس سرآیند از سایر شماره‌های نسخه معتبر نیز پشتیبانی می‌کند. اگر یک شماره نسخه مقدار معتبری مطابق RFC 2045 داشته باشد، شیء سرآیند برای ویژگی‌های زیر مقادیر غیر None خواهد داشت:

version

شماره نسخه به‌صورت یک رشته، با حذف هرگونه فضای سفید و/یا کامنت.

major

شماره نسخه اصلی به‌صورت عدد صحیح

minor

شماره نسخه فرعی به‌صورت عدد صحیح

class email.headerregistry.ParameterizedMIMEHeader

همه سرآیندهای MIME با پیشوند 'Content-' شروع می‌شوند. هر سرآیند خاص، مقدار معینی دارد که در ذیل کلاس مربوط به آن سرآیند توضیح داده شده است. برخی نیز می‌توانند فهرستی از پارامترهای تکمیلی را بپذیرند که قالب مشترکی دارند. این کلاس به‌عنوان پایه‌ای برای همه سرآیندهای MIME که پارامتر می‌پذیرند، عمل می‌کند.

params

یک دیکشنری که نام‌های پارامتر را به مقادیر پارامتر نگاشت می‌کند.

class email.headerregistry.ContentTypeHeader

یک کلاس ParameterizedMIMEHeader که سرآیند Content-Type را مدیریت می‌کند.

content_type

رشته‌ی نوع محتوا، در قالب maintype/subtype.

maintype
subtype
class email.headerregistry.ContentDispositionHeader

یک کلاس ParameterizedMIMEHeader که سرآیند Content-Disposition را مدیریت می‌کند.

content_disposition

تنها مقادیر معتبرِ رایج، inline و attachment هستند.

class email.headerregistry.ContentTransferEncodingHeader

سرآیند Content-Transfer-Encoding را مدیریت می‌کند.

cte

مقادیر معتبر عبارتند از 7bit، 8bit، base64 و quoted-printable. برای اطلاعات بیشتر RFC 2045 را ببینید.

class email.headerregistry.HeaderRegistry(base_class=BaseHeader, default_class=UnstructuredHeader, use_default_map=True)

این کارخانه‌ای است که EmailPolicy به‌طور پیش‌فرض از آن استفاده می‌کند. HeaderRegistry با استفاده از base_class و یک کلاس تخصصی بازیابی‌شده از رجیستری که در اختیار دارد، به‌صورت پویا کلاسی را می‌سازد که برای ایجاد یک نمونه سرآیند استفاده می‌شود. هنگامی که یک نام سرآیند معین در رجیستری وجود نداشته باشد، کلاس مشخص‌شده توسط default_class به‌عنوان کلاس تخصصی استفاده می‌شود. هنگامی که use_default_map برابر True باشد (مقدار پیش‌فرض)، نگاشت استاندارد نام‌های سرآیند به کلاس‌ها در حین مقداردهی اولیه به رجیستری کپی می‌شود. base_class همیشه آخرین کلاس در فهرست __bases__ کلاس ساخته‌شده است.

نگاشت‌های پیش‌فرض عبارتند از:

subject:

UniqueUnstructuredHeader

date:

UniqueDateHeader

resent-date:

DateHeader

orig-date:

UniqueDateHeader

sender:

UniqueSingleAddressHeader

resent-sender:

SingleAddressHeader

to:

UniqueAddressHeader

resent-to:

AddressHeader

cc:

UniqueAddressHeader

resent-cc:

AddressHeader

bcc:

UniqueAddressHeader

resent-bcc:

AddressHeader

from:

UniqueAddressHeader

resent-from:

AddressHeader

reply-to:

UniqueAddressHeader

mime-version:

MIMEVersionHeader

content-type:

ContentTypeHeader

content-disposition:

ContentDispositionHeader

content-transfer-encoding:

ContentTransferEncodingHeader

message-id:

MessageIDHeader

HeaderRegistry متدهای زیر را دارد:

map_to_type(self, name, cls)

name نام سرآیندی است که باید نگاشت شود. این نام در رجیستری به حروف کوچک تبدیل می‌شود. cls کلاس تخصصی است که به همراه base_class، برای ایجاد کلاسی به کار می‌رود که سرآیندهای منطبق با name را نمونه‌سازی می‌کند.

__getitem__(name)

یک کلاس را برای مدیریت ایجاد سرآیند name بسازید و برگردانید.

__call__(name, value)

سرآیند اختصاصی مرتبط با name را از رجیستری بازیابی می‌کند (اگر name در رجیستری وجود نداشته باشد، از default_class استفاده می‌شود) و آن را با base_class ترکیب می‌کند تا کلاسی تولید شود، سازنده‌ی کلاس ساخته‌شده را با همان فهرست آرگومان‌ها فراخوانی می‌کند و در نهایت نمونه‌ی کلاس ایجادشده از این طریق را برمی‌گرداند.

کلاس‌های زیر کلاس‌هایی هستند که برای نمایش داده‌های تجزیه‌شده از سرآیندهای ساخت‌یافته استفاده می‌شوند و به‌طور کلی یک برنامه کاربردی می‌تواند از آن‌ها برای ساخت مقادیر ساخت‌یافته جهت انتساب به سرآیندهای مشخص استفاده کند.

class email.headerregistry.Address(display_name='', username='', domain='', addr_spec=None)

کلاسی که برای نمایش یک نشانی ایمیل استفاده می‌شود. شکل کلی یک نشانی به این صورت است:

[display_name] <username@domain>

یا:

username@domain

که هر بخش باید با قواعد سینتکسی خاصی که در RFC 5322 تشریح شده است مطابقت داشته باشد.

As a convenience addr_spec can be specified instead of username and domain, in which case username and domain will be parsed from the addr_spec. An addr_spec must be a properly RFC quoted string; if it is not Address will raise an error. Unicode characters are allowed and will be property encoded when serialized. However, per the RFCs, Unicode is not allowed in the username portion of the address.

display_name

بخش نام نمایشی نشانی، در صورت وجود، با حذف تمام علامت‌های نقل‌قول. اگر نشانی نام نمایشی نداشته باشد، این ویژگی یک رشته خالی خواهد بود.

username

بخش username از نشانی، با حذف تمام علامت‌های نقل‌قول.

domain

بخش domain از نشانی.

addr_spec

بخش username@domain از نشانی، که به‌درستی در علامت نقل‌قول قرار گرفته است تا به‌عنوان یک نشانی ساده (دومین شکل نشان‌داده‌شده در بالا) استفاده شود. این ویژگی تغییرپذیر نیست.

__str__()

مقدار str شیء، نشانی نقل‌قول‌شده مطابق قواعد RFC 5322 است، اما بدون کدگذاری انتقال محتوا (Content Transfer Encoding) برای هیچ‌یک از نویسه‌های غیر ASCII.

برای پشتیبانی از SMTP (RFC 5321Address یک حالت خاص را مدیریت می‌کند: اگر username و domain هر دو رشته خالی (یا None) باشند، مقدار رشته‌ای Address برابر <> است.

class email.headerregistry.Group(display_name=None, addresses=None)

کلاسی که برای بازنمایی یک گروه نشانی استفاده می‌شود. شکل کلی یک گروه نشانی به این صورت است:

display_name: [address-list];

برای سهولت در پردازش فهرست‌هایی از نشانی‌ها که شامل ترکیبی از گروه‌ها و نشانی‌های تکی هستند، می‌توان از Group همچنین برای نمایش نشانی‌های تکی که بخشی از یک گروه نیستند استفاده کرد؛ برای این کار display_name را روی None تنظیم کنید و فهرستی از نشانی تکی را به‌عنوان addresses ارائه دهید.

display_name

display_name گروه. اگر این مقدار None باشد و دقیقاً یک Address در addresses وجود داشته باشد، آنگاه Group نشان‌دهنده‌ی یک نشانی واحد است که در گروهی نیست.

addresses

یک تاپل احتمالاً خالی از اشیای Address که نشان‌دهنده‌ی نشانی‌های درون گروه هستند.

__str__()

مقدار str یک Group مطابق RFC 5322 قالب‌بندی می‌شود، اما بدون اعمال کدگذاری انتقال محتوا (Content Transfer Encoding) بر هیچ‌یک از نویسه‌های غیر ASCII. اگر display_name وجود نداشته باشد و تنها یک Address در فهرست addresses وجود داشته باشد، مقدار str برابر با str همان Address تنها خواهد بود.

پانویس‌ها