ارسال یک ایمیل
`emails.send`: یک پیام، حالا یا بعداً.
emails.send
from openemail import openemail email = openemail.emails.send({ 'from': {'email': '[email protected]', 'name': 'Acme Billing'}, 'to': ['[email protected]', 'Grace <[email protected]>'], 'cc': '[email protected]', 'bcc': [{'email': '[email protected]'}], 'replyTo': '[email protected]', 'subject': 'Your September invoice', 'html': '<p>Invoice attached.</p>', 'text': 'Invoice attached.', 'headers': {'X-Campaign': 'invoices'}, 'attachments': [{'filename': 'invoice.pdf', 'content': pdf_bytes}], 'threadId': 'thread_…', 'scheduledAt': 'PT1H', 'tags': {'order': '4021'}, 'tracking': {'opens': True, 'clicks': True},})to، cc و bcc یک گیرنده یا چند گیرنده میگیرند، و اگر یکی تنها بدهید برایتان پیچیده میشود. هرکدام میتواند نشانی خام، Name <addr@host> یا {'email': ..., 'name': ...} باشد.
پارامترها
fromRecipientInputالزامی- فرستنده. یک نشانی خام، `Name <addr@host>` یا یک دیکشنری. باید نشانیای باشد که این کلید اجازهٔ ارسال با آن را دارد. هیچ فرستندهٔ جایگزینی وجود ندارد، پس هر ارسال همیشه نشانیای را که از آن فرستاده میشود نام میبرد.
toRecipientInput | list[RecipientInput]الزامی- یک گیرنده یا چند گیرنده؛ اگر یکی تنها بدهید برایتان پیچیده میشود. حداکثر 50 نشانی روی هم در to، cc و bcc.
ccRecipientInput | list[RecipientInput]- به سقف 50 گیرنده شمرده میشود.
bccRecipientInput | list[RecipientInput]- هرگز در بایتهایی که دیگران دریافت میکنند نام برده نمیشود، چون به ازای هر گیرنده یک پاکت منتقل میشود.
replyToRecipientInput- یک نشانی تکی، که به شکل هدر Reply-To فرستاده میشود.
subjectstr- حداکثر 998 نویسه، همان حد طول خط RFC 5322. پیشفرض: خالی.
htmlstr- یکی از html، text، draftId یا template الزامی است. وقتی هر دو html و text داده شوند، آنچه گیرندگان میبینند HTML است.
textstr- بخش متن ساده.
templateEmailSendTemplate- یک قالب ذخیرهشده را سمت سرور رندر میکند. `version` آن را سنجاق میکند؛ ننویسیدش تا هرچه هنگام پذیرش درخواست منتشر شده باشد به کار رود. prop ناشناخته یا نیامده، بهجای جای خالی در پیام، یک 422 است.
draftIdstr- یک پیشنویس ذخیرهشده را زیر این پاکت بفرستید.
headersdict[str, str]- `X-*`، `List-*`، Reply-To، Precedence، Auto-Submitted، Importance، Priority و Feedback-Id. هر چیزی که خودِ حملونقل تنظیم میکند بهجای حذف بیسروصدا رد میشود.
attachmentslist[AttachmentInput]- `{'filename': ..., 'content': ...}` با یک `'contentType'` اختیاری، یا `{'fileId': ...}` که فایلی را نام میبرد که از پیش در فضای کاری هست، مثلاً فایلی از `files.upload`. برای content بایت بدهید تا برایتان با base64 رمزگذاری شود. 20 فایل، با سقف مجموع 5 MB برای فایلهای درونخطی پس از رمزگشایی. فایل ذخیرهشده میتواند بزرگتر باشد و به شکل پیوند دانلود میرود.
attachmentDeliveryAttachmentDeliveryMode- `mime`، `link` یا `auto`. `auto` فایلها را وقتی روی دامنهای با files domain فعال از 2 MB بگذرند به شکل پیوند دانلود میبرد و در غیر این صورت درون پیام. اگر ننویسید، تنظیم صندوق اعمال میشود، که پیشفرضش `auto` است.
threadIdstr- پاسخدادن درون یک thread موجود. حملونقل In-Reply-To و References را مینویسد.
scheduledAtdatetime | str- یک `datetime`، یک لحظهٔ ISO-8601، یا مدتی مانند `PT1H`. تا یک سال بعد، هرگز در گذشته. نمیشود با cancellableForSeconds ترکیبش کرد.
cancellableForSecondsint- 0 تا 900. پنجرهٔ لغو روی یک ارسال فوری: همان سازوکار لغوِ composer، که بهجای hardcode شدن در دسترس گذاشته شده است.
tagsdict[str, str]- تا 10 برچسب، که بازتاب داده میشوند و قابل فیلترند. هرگز تفسیر نمیشوند.
signaturebool- اینکه این پیام امضای نشانی فرستنده را داشته باشد یا نه: امضای خودش، وگرنه امضای catch-all برای نشانیای که catch-all دریافت کرده، وگرنه پانویس OpenEmail، مگر اینکه آن نشانی خاموشش کرده باشد. اگر مشخص نشود، بدنهٔ `html` دقیقاً همانطور که نوشته شده و بدون امضا میرود و بدنهٔ فقط `text` آن را دارد. برای نامهای که برنامهای از طرف کسی میفرستد، مثل رسید، بازنشانی گذرواژه یا خلاصه، `False` بگذارید؛ هیچکدام امضای یک شخص را زیر خود نمیخواهند.
trackingTrackingRequest- اینکه آیا برای این پیام pixel باز شدن افزوده و پیوندها بازنویسی شوند یا نه. خاموش است مگر ردیابی برای نشانیای که پیام از آن میرود (یا catch-allای که آن را گرفته) روشن شده باشد، و هر یک از این فیلدها که اینجا بیاید تکلیف همان یک پیام را، هرطور که نشانی تنظیم شده باشد، روشن میکند.
translateSendTranslateOptions- آن را به زبان گیرنده بفرستید. `to` یک کد، یک نام انگلیسی یا نام خودِ زبان میگیرد؛ `subject` و `includeOriginal` هر دو پیشفرض true دارند. هنگام پذیرفتهشدن درخواست حل میشود، پس پیام زمانبندیشده همان کلماتی را میبرد که تأیید شدهاند. در کنار `draftId` رد میشود.
پاسخ
idstr- شناسهٔ ارسال، `msg_…`. برای `get`، `cancel`، `reschedule` و `get_tracking` از آن استفاده کنید.
statusEmailStatus- queued، scheduled، sending، sent، partial، bounced، cancelled یا failed. بهجای این واقعیت که فراخوانی برگشت، همین را بخوانید. `partial` وضعیتی از آنِ خودش است: بعضی گیرندگان پیام را دریافت کردهاند و نمیشود پس گرفت، پس تلاش دوباره اشتباه است و گزارش شکست دروغ.
modeApiKeyMode- کدام نوع کلید آن را فرستاده. ارسال در حالت test ثبت میشود و هرگز منتقل نمیشود.
fromstr- نشانیای که واقعاً مجاز شمرده و روی سیم گذاشته شد، که همیشه همان نشانی درخواستشده نیست.
subjectstr | None- همانطور که فرستاده شد.
messageIdstr | None- همان Message-ID مربوط به RFC 5322. تا وقتی MIME وجود نداشته باشد null است. سرویس ارسال هدر را در مسیر خروج بازنویسی میکند، پس هیچ bounce یا گزارش تحویلی این مقدار را حمل نمیکند. چیزی که رویداد با آن برمیگردد `id` است.
threadIdstr | None- thread ای که در آن نشست.
transportEmailTransport | str | None- پیام چگونه رفت. تا پیش از ارسال null است.
attemptsint- چند بار ارسال تلاش شده است.
lastErrorstr | None- چرا آخرین تلاش شکست خورد، عیناً.
scheduledAtstr | None- لحظهٔ ISO که باید برود.
cancellableUntilstr | None- تا وقتی اکنون پیش از این لحظه است، لغو هنوز کار میکند.
sentAtstr | None- لحظهٔ ISO که رفت.
tagsdict[str, str]- آنچه فرستادید، بازتابدادهشده.
sourceEmailSource | str- composer، api، mcp، ai، oauth یا form: کدام سطح درخواست داده است. `api` همین کلاینت با کلید API است، و `oauth` همین کلاینت با توکن دسترسی.
createdAtstr- لحظهٔ ISO که رکورد نوشته شد.
replayedbool- وقتی True است که یک Idempotency-Key با ارسالی که از پیش وجود داشته مطابقت کرده باشد. چیز تازهای فرستاده نشده، و این همان پیام اصلی است.
translationNotRequired[EmailTranslationResource]- فقط روی پیامی حاضر است که ترجمه شده، و تنها جایی که کل درخواست ذخیرهشده حمل میشود: همین پاسخ و `get`. یک دیکشنری از `language`، `languageName`، `detectedSourceLanguage`، `subject` و `includeOriginal`، همه به شکل کد نه ردیف زبان. ردیف فهرست هرگز آن را ندارد، پس غیابش آنجا به هیچ سمتی چیزی نمیگوید. آن را با `email.get('translation')` بخوانید.
به زبان گیرنده
translate پیام را پیش از رفتنش به زبان کسی دیگر مینویسد. بدنه (و موضوع، مگر آن را خاموش کنید) وقتی API درخواست را میپذیرد ترجمه میشود، و آنچه بیرون آمد همان است که بیرون میرود: ترجمهای که نشود تولیدش کرد، بهجای فرستادن پیام به زبانی که نوشتهاید، ارسال را رد میکند.
from openemail import openemail email = openemail.emails.send({ 'from': '[email protected]', 'to': '[email protected]', 'subject': 'Your September invoice', 'html': '<p>Invoice attached. Payment is due on the 14th.</p>', 'translate': {'to': 'de'},}) print(email.get('translation'))کسی پیش از رفتنش آن را نخواند. emails.translate همان رفتوبرگشت است که یک گام زودتر متوقف شده. آن را به یک آدم نشان دهید، بگذارید تغییرش دهد، و بعد آنچه را تأیید کرده بدون هیچ translate ای روی فراخوانی بفرستید. دادن دوبارهٔ آن، متن را بار دوم ترجمه میکرد و ویرایشهایش را دور میریخت.
from openemail import openemail preview = openemail.emails.translate({ 'subject': 'Your September invoice', 'html': '<p>Invoice attached. Payment is due on the 14th.</p>', 'to': 'de',}) print(preview['language']['native'], preview['detectedSourceLanguage'])print(preview['html']) approved_subject = input(f"Subject [{preview['subject']}]: ") or preview['subject'] or '' openemail.emails.send({ 'from': '[email protected]', 'to': '[email protected]', 'subject': approved_subject, 'html': preview['html'] or '',})from openemail import LANGUAGES, is_rtl_language, language_by_code, openemail, resolve_language current = openemail.languages.list() german = resolve_language('Deutsch')traditional = resolve_language('zh-TW')upper = language_by_code('DE') assert len(LANGUAGES) == 200assert german is not None and german['code'] == 'de'assert traditional is not None and traditional['code'] == 'zh-Hant'assert upper is not None and upper['native'] == 'Deutsch'assert is_rtl_language('ar')این جدول درون پکیج هست، به ترتیب picker، پس میشود یک picker را پیش از نخستین درخواست پر کرد. languages.list() همان ردیفها را از روی سیم، به شکل فهرستی ساده، برمیگرداند، برای فراخوانندهای که ردیفهای کنونی را به ردیفهایی که این نسخه با آنها عرضه شده ترجیح میدهد. resolve_language یک کد، یک نام انگلیسی، یک نام بومی یا یک نام مستعار میگیرد (zh-TW نام مستعار کدی است که دیگر فهرست نمیشود)، language_by_code کد را دقیقاً و بدون حساسیت به بزرگی و کوچکی حروف تطبیق میدهد، و شانزده ردیف از راست به چپاند. native، label و code را با هم جستوجو کنید، native را اول نشان دهید، و کد را ذخیره کنید.
emails.translate بهطور خودکار دوباره تلاش نمیشود. فراخوانی مدل خرج میکند و چیزی نمینویسد، پس چیزی برای idempotent کردن نیست و تلاش دوباره پس از درخواستی بیپاسخ فقط همان پاسخ را دو بار میخرد.
- زبانی که به هیچچیز حل نشود یک
validation_errorرویtranslate.toاست، پیش از آنکه چیزی فرستاده شود. translation_too_longبرای بیش از 30,000 نویسه،translation_not_configuredوقتی نصب هیچ AI پیکربندیشدهای ندارد، یک 429 باai_quota_exceededوقتی آن فضای کاری کنشهای هوش مصنوعی امروز را مصرف کرده باشد (در نیمهشب UTC بازنشانی میشود و تلاش دوباره نمیشود)،translation_failedوقتی ارائهدهنده پاسخ نداده است. هیچکدام بهعنوان جایگزین، پیام را ترجمهنشده نمیفرستند.- با
templateکار میکند: آنچه ترجمه میشود خروجیِ RENDER شده است، پس یک بدنهٔ ذخیرهشده به هر زبانی که مشتریانتان میخوانند خدمت میکند. قالبی که یک سند کامل رندر میکند، doctype، بلوکهای<style>و قاعدههای@font-faceخود را نگه میدارد: فقط بدنه به مدل میرود و بقیه دوباره دورش گذاشته میشود.<title>آن دستنخورده میماند، که بههرحال چیزی نمایشش نمیدهد. - تلاش دوباره هزینهٔ اضافه ندارد. ترجمه بخشی از اثرانگشت idempotency نیست (خودِ درخواست هست، با
translateو همه)، پس بازفرستادن یک ارسال بیپاسخ با همانIdempotency-Keyپیامی را که از پیش وجود دارد بازپخش میکند، نه اینکه بار دوم ترجمه و ارسال کند. - پیام ترجمهشدهای که queued یا scheduled باشد در برابر تغییر واژهها منجمد است.
emails.rescheduleهنوز جابهجایش میکند؛ تغییر آنچه میگوید یعنی لغو و ارسال دوباره.
پیوستها
content روی سیم base64 است. بایت بدهید تا برایتان رمزگذاری شود.
from pathlib import Path from openemail.types import AttachmentInput attachments: list[AttachmentInput] = [ { 'filename': 'invoice.pdf', 'content': Path('invoice.pdf').read_bytes(), 'contentType': 'application/pdf', },]to_base64 export شده است، اگر جای دیگری لازمش دارید. یک str در content همانطور که هست فرستاده میشود، پس باید از پیش base64 باشد.