taolib.testing.email_service#
邮件服务系统。
提供完整的事务性邮件和营销邮件发送、模板管理、投递追踪和退订管理功能。 支持多个邮件服务提供商(SendGrid、Mailgun、Amazon SES、SMTP)自动故障转移。
Submodules#
- taolib.testing.email_service.cli
- taolib.testing.email_service.errors
- taolib.testing.email_service.events
- taolib.testing.email_service.models
- taolib.testing.email_service.providers
- taolib.testing.email_service.queue
- taolib.testing.email_service.repository
- taolib.testing.email_service.server
- taolib.testing.email_service.services
- taolib.testing.email_service.template
Exceptions#
所有提供商均发送失败。 |
|
邮件记录未找到。 |
|
邮件服务基础异常。 |
|
邮件提供商通信错误。 |
|
队列操作错误。 |
|
订阅操作错误。 |
|
模板未找到。 |
|
模板渲染失败。 |
Classes#
Bounce classification. |
|
Email attachment metadata. |
|
Email creation request. |
|
Email MongoDB document. |
|
Email sending priority. |
|
Email recipient with optional display name. |
|
Email API response. |
|
Email delivery status. |
|
Email category type. |
|
Email service provider type. |
|
Subscription MongoDB document. |
|
Subscription API response. |
|
Subscription status. |
|
Template creation request. |
|
Template MongoDB document. |
|
Template API response. |
|
Template update request (all fields optional). |
|
Tracking event MongoDB document. |
|
Tracking event API response. |
|
Tracking event type for email analytics. |
|
邮件提供商协议。 |
|
Mailgun 邮件提供商。 |
|
提供商故障转移管理器。 |
|
提供商健康状态。 |
|
SendGrid 邮件提供商。 |
|
提供商发送结果。 |
|
Amazon SES 邮件提供商。 |
|
邮件队列协议。 |
|
内存邮件队列。 |
|
Redis 邮件队列。 |
|
退信处理器。 |
|
邮件分析数据。 |
|
核心邮件发送服务。 |
|
邮件队列处理器。 |
|
订阅管理服务。 |
|
模板管理服务。 |
|
追踪和分析服务。 |
|
渲染后的邮件内容。 |
|
Jinja2 沙箱模板引擎。 |
Package Contents#
- exception taolib.testing.email_service.AllProvidersFailedError(errors: list[tuple[str, str]] | None = None)#
Bases:
ProviderError所有提供商均发送失败。
- errors = []#
- exception taolib.testing.email_service.EmailNotFoundError#
Bases:
EmailServiceError邮件记录未找到。
- exception taolib.testing.email_service.ProviderError#
Bases:
EmailServiceError邮件提供商通信错误。
- exception taolib.testing.email_service.QueueError#
Bases:
EmailServiceError队列操作错误。
- exception taolib.testing.email_service.SubscriptionError#
Bases:
EmailServiceError订阅操作错误。
- exception taolib.testing.email_service.TemplateNotFoundError#
Bases:
EmailServiceError模板未找到。
- exception taolib.testing.email_service.TemplateRenderError#
Bases:
EmailServiceError模板渲染失败。
- class taolib.testing.email_service.BounceType#
Bases:
enum.StrEnumBounce classification.
- HARD = 'hard'#
- SOFT = 'soft'#
- UNDETERMINED = 'undetermined'#
- class taolib.testing.email_service.EmailAttachment#
Bases:
pydantic.BaseModelEmail attachment metadata.
- class taolib.testing.email_service.EmailCreate#
Bases:
EmailBaseEmail creation request.
- attachments: list[EmailAttachment]#
- schedule_at: datetime.datetime | None#
- class taolib.testing.email_service.EmailDocument#
Bases:
EmailBaseEmail MongoDB document.
- attachments: list[EmailAttachment]#
- schedule_at: datetime.datetime | None#
- sent_at: datetime.datetime | None#
- delivered_at: datetime.datetime | None#
- opened_at: datetime.datetime | None#
- created_at: datetime.datetime#
- updated_at: datetime.datetime#
- model_config#
- to_response() EmailResponse#
Convert to API response model.
- class taolib.testing.email_service.EmailPriority#
Bases:
enum.StrEnumEmail sending priority.
- HIGH = 'high'#
- NORMAL = 'normal'#
- LOW = 'low'#
- class taolib.testing.email_service.EmailRecipient#
Bases:
pydantic.BaseModelEmail recipient with optional display name.
- class taolib.testing.email_service.EmailResponse#
Bases:
EmailBaseEmail API response.
- sent_at: datetime.datetime | None#
- delivered_at: datetime.datetime | None#
- opened_at: datetime.datetime | None#
- created_at: datetime.datetime#
- updated_at: datetime.datetime#
- model_config#
- class taolib.testing.email_service.EmailStatus#
Bases:
enum.StrEnumEmail delivery status.
- QUEUED = 'queued'#
- SENDING = 'sending'#
- SENT = 'sent'#
- DELIVERED = 'delivered'#
- OPENED = 'opened'#
- CLICKED = 'clicked'#
- BOUNCED = 'bounced'#
- FAILED = 'failed'#
- REJECTED = 'rejected'#
- class taolib.testing.email_service.EmailType#
Bases:
enum.StrEnumEmail category type.
- TRANSACTIONAL = 'transactional'#
- MARKETING = 'marketing'#
- class taolib.testing.email_service.ProviderType#
Bases:
enum.StrEnumEmail service provider type.
- SENDGRID = 'sendgrid'#
- MAILGUN = 'mailgun'#
- SES = 'ses'#
- SMTP = 'smtp'#
- class taolib.testing.email_service.SubscriptionDocument#
Bases:
pydantic.BaseModelSubscription MongoDB document.
Tracks whether a recipient has unsubscribed from marketing emails.
- subscribed_at: datetime.datetime#
- unsubscribed_at: datetime.datetime | None#
- created_at: datetime.datetime#
- updated_at: datetime.datetime#
- model_config#
- to_response() SubscriptionResponse#
Convert to API response model.
- class taolib.testing.email_service.SubscriptionResponse#
Bases:
pydantic.BaseModelSubscription API response.
- subscribed_at: datetime.datetime#
- unsubscribed_at: datetime.datetime | None = None#
- created_at: datetime.datetime#
- updated_at: datetime.datetime#
- model_config#
- class taolib.testing.email_service.SubscriptionStatus#
Bases:
enum.StrEnumSubscription status.
- ACTIVE = 'active'#
- UNSUBSCRIBED = 'unsubscribed'#
- class taolib.testing.email_service.TemplateCreate#
Bases:
TemplateBaseTemplate creation request.
- class taolib.testing.email_service.TemplateDocument#
Bases:
TemplateBaseTemplate MongoDB document.
- created_at: datetime.datetime#
- updated_at: datetime.datetime#
- model_config#
- to_response() TemplateResponse#
Convert to API response model.
- class taolib.testing.email_service.TemplateResponse#
Bases:
TemplateBaseTemplate API response.
- created_at: datetime.datetime#
- updated_at: datetime.datetime#
- model_config#
- class taolib.testing.email_service.TemplateUpdate#
Bases:
pydantic.BaseModelTemplate update request (all fields optional).
- email_type: taolib.testing.email_service.models.enums.EmailType | None = None#
- class taolib.testing.email_service.TrackingEventDocument#
Bases:
TrackingEventBaseTracking event MongoDB document.
- bounce_type: taolib.testing.email_service.models.enums.BounceType | None#
- created_at: datetime.datetime#
- model_config#
- to_response() TrackingEventResponse#
Convert to API response model.
- class taolib.testing.email_service.TrackingEventResponse#
Bases:
TrackingEventBaseTracking event API response.
- bounce_type: taolib.testing.email_service.models.enums.BounceType | None#
- created_at: datetime.datetime#
- model_config#
- class taolib.testing.email_service.TrackingEventType#
Bases:
enum.StrEnumTracking event type for email analytics.
- SENT = 'sent'#
- DELIVERED = 'delivered'#
- OPENED = 'opened'#
- CLICKED = 'clicked'#
- BOUNCED = 'bounced'#
- COMPLAINED = 'complained'#
- UNSUBSCRIBED = 'unsubscribed'#
- class taolib.testing.email_service.EmailProviderProtocol#
Bases:
Protocol邮件提供商协议。
所有邮件服务提供商必须实现此协议。
- async send(email: taolib.testing.email_service.models.email.EmailDocument) SendResult#
发送单封邮件。
- 参数:
email -- 邮件文档
- 返回:
发送结果
- async send_bulk(emails: list[taolib.testing.email_service.models.email.EmailDocument]) list[SendResult]#
批量发送邮件。
- 参数:
emails -- 邮件文档列表
- 返回:
发送结果列表
- async check_health() ProviderHealthStatus#
检查提供商健康状态。
- 返回:
健康状态
- class taolib.testing.email_service.MailgunProvider(api_key: str, domain: str)#
Mailgun 邮件提供商。
通过 Mailgun HTTP API 发送邮件。
- _api_key#
- _domain#
- _client#
- async send(email: taolib.testing.email_service.models.email.EmailDocument) taolib.testing.email_service.providers.protocol.SendResult#
通过 Mailgun API 发送邮件。
- async send_bulk(emails: list[taolib.testing.email_service.models.email.EmailDocument]) list[taolib.testing.email_service.providers.protocol.SendResult]#
批量发送(逐封发送)。
- async check_health() taolib.testing.email_service.providers.protocol.ProviderHealthStatus#
检查 Mailgun 可用性。
- _build_form_data(email: taolib.testing.email_service.models.email.EmailDocument) dict#
构建 Mailgun 表单数据。
- class taolib.testing.email_service.ProviderFailoverManager(providers: list[tuple[taolib.testing.email_service.providers.protocol.EmailProviderProtocol, int]], max_consecutive_failures: int = 3, cooldown_seconds: int = 60)#
提供商故障转移管理器。
按优先级排序提供商,自动在主提供商失败时切换到备用提供商。 每个提供商独立跟踪健康状态,失败超过阈值后进入冷却期。
- _states: list[_ProviderState]#
- _max_failures = 3#
- _cooldown_seconds = 60#
- async send(email: taolib.testing.email_service.models.email.EmailDocument) taolib.testing.email_service.providers.protocol.SendResult#
通过可用提供商发送邮件,自动故障转移。
- 参数:
email -- 邮件文档
- 返回:
发送结果
- 抛出:
AllProvidersFailedError -- 所有提供商均失败
- async send_bulk(emails: list[taolib.testing.email_service.models.email.EmailDocument]) list[taolib.testing.email_service.providers.protocol.SendResult]#
批量发送邮件。
- 参数:
emails -- 邮件文档列表
- 返回:
发送结果列表
- get_provider_statuses() list[taolib.testing.email_service.providers.protocol.ProviderHealthStatus]#
获取所有提供商状态。
- 返回:
提供商健康状态列表
- class taolib.testing.email_service.ProviderHealthStatus#
提供商健康状态。
- last_check: datetime.datetime | None = None#
- class taolib.testing.email_service.SendGridProvider(api_key: str, sender_email: str | None = None, sender_name: str | None = None)#
SendGrid 邮件提供商。
通过 SendGrid v3 Mail Send API 发送邮件。
- _api_key#
- _sender_email = None#
- _sender_name = None#
- _client#
- async send(email: taolib.testing.email_service.models.email.EmailDocument) taolib.testing.email_service.providers.protocol.SendResult#
通过 SendGrid API 发送邮件。
- async send_bulk(emails: list[taolib.testing.email_service.models.email.EmailDocument]) list[taolib.testing.email_service.providers.protocol.SendResult]#
批量发送(逐封发送)。
- async check_health() taolib.testing.email_service.providers.protocol.ProviderHealthStatus#
检查 SendGrid 可用性。
- _build_payload(email: taolib.testing.email_service.models.email.EmailDocument) dict#
构建 SendGrid v3 API 请求体。
- class taolib.testing.email_service.SendResult#
提供商发送结果。
- class taolib.testing.email_service.SESProvider(region: str, access_key_id: str, secret_access_key: str)#
Amazon SES 邮件提供商。
通过 Amazon SES v2 HTTP API 发送邮件。 需要配置 AWS 凭证和区域。
- _region#
- _access_key_id#
- _secret_access_key#
- _endpoint#
- _client#
- async send(email: taolib.testing.email_service.models.email.EmailDocument) taolib.testing.email_service.providers.protocol.SendResult#
通过 SES API 发送邮件。
使用简化的 SES v2 SendEmail API。 生产环境建议使用 aiobotocore 以获得完整的 AWS 签名支持。
- async send_bulk(emails: list[taolib.testing.email_service.models.email.EmailDocument]) list[taolib.testing.email_service.providers.protocol.SendResult]#
批量发送(逐封发送)。
- async check_health() taolib.testing.email_service.providers.protocol.ProviderHealthStatus#
检查 SES 可用性。
- _build_payload(email: taolib.testing.email_service.models.email.EmailDocument) dict#
构建 SES v2 请求体。
- class taolib.testing.email_service.EmailQueueProtocol#
Bases:
Protocol邮件队列协议。
所有队列实现必须符合此协议。
- async enqueue(email_id: str, priority: taolib.testing.email_service.models.enums.EmailPriority = EmailPriority.NORMAL) None#
将邮件 ID 加入队列。
- 参数:
email_id -- 邮件 ID
priority -- 优先级
- async enqueue_bulk(email_ids: list[str], priority: taolib.testing.email_service.models.enums.EmailPriority = EmailPriority.NORMAL) None#
批量加入队列。
- 参数:
email_ids -- 邮件 ID 列表
priority -- 优先级
- class taolib.testing.email_service.InMemoryEmailQueue#
内存邮件队列。
使用 asyncio.PriorityQueue 实现,仅用于测试。
- _queue: asyncio.PriorityQueue[tuple[int, str]]#
- async enqueue(email_id: str, priority: taolib.testing.email_service.models.enums.EmailPriority = EmailPriority.NORMAL) None#
将邮件 ID 加入队列。
- async enqueue_bulk(email_ids: list[str], priority: taolib.testing.email_service.models.enums.EmailPriority = EmailPriority.NORMAL) None#
批量加入队列。
- class taolib.testing.email_service.RedisEmailQueue(redis_client: redis.asyncio.Redis)#
Redis 邮件队列。
使用三个 Redis List 实现优先级队列: - email:queue:high (高优先级) - email:queue:normal (普通优先级) - email:queue:low (低优先级)
BRPOP 按顺序检查三个列表,自然实现优先级。
- _redis#
- async enqueue(email_id: str, priority: taolib.testing.email_service.models.enums.EmailPriority = EmailPriority.NORMAL) None#
将邮件 ID 加入队列。
- async enqueue_bulk(email_ids: list[str], priority: taolib.testing.email_service.models.enums.EmailPriority = EmailPriority.NORMAL) None#
批量加入队列。
- class taolib.testing.email_service.BounceHandler(tracking_service: taolib.testing.email_service.services.tracking_service.TrackingService, subscription_service: taolib.testing.email_service.services.subscription_service.SubscriptionService, email_repo: taolib.testing.email_service.repository.email_repo.EmailRepository, hard_bounce_threshold: int = 1)#
退信处理器。
- _tracking#
- _subscription#
- _email_repo#
- _hard_bounce_threshold = 1#
- async handle_bounce(email_id: str, bounce_type: taolib.testing.email_service.models.enums.BounceType, reason: str, recipient: str, provider: str | None = None, raw_payload: dict | None = None) None#
处理退信事件。
- 参数:
email_id -- 邮件 ID
bounce_type -- 退信类型
reason -- 退信原因
recipient -- 收件人
provider -- 提供商名称
raw_payload -- 原始 Webhook 数据
- class taolib.testing.email_service.EmailAnalytics#
Bases:
pydantic.BaseModel邮件分析数据。
- class taolib.testing.email_service.EmailService(email_repo: taolib.testing.email_service.repository.email_repo.EmailRepository, template_service: taolib.testing.email_service.services.template_service.TemplateService, subscription_service: taolib.testing.email_service.services.subscription_service.SubscriptionService, provider_manager: taolib.testing.email_service.providers.failover.ProviderFailoverManager, queue: taolib.testing.email_service.queue.protocol.EmailQueueProtocol, tracking_service: taolib.testing.email_service.services.tracking_service.TrackingService)#
核心邮件发送服务。
编排完整的邮件发送流程: 1. 模板渲染(如有模板) 2. 订阅状态检查(营销邮件) 3. 创建邮件文档 4. 入队或直接发送
- _email_repo#
- _template_service#
- _subscription_service#
- _provider_manager#
- _queue#
- _tracking_service#
- async send_email(data: taolib.testing.email_service.models.email.EmailCreate, enqueue: bool = True) taolib.testing.email_service.models.email.EmailResponse#
发送单封邮件。
- 参数:
data -- 邮件创建数据
enqueue -- 是否入队异步发送,False 则直接发送
- 返回:
邮件响应
- async send_bulk(emails: list[taolib.testing.email_service.models.email.EmailCreate]) list[taolib.testing.email_service.models.email.EmailResponse]#
批量发送邮件。
- async _send_now(email_doc: taolib.testing.email_service.models.email.EmailDocument) taolib.testing.email_service.models.email.EmailDocument#
立即发送邮件。
- 参数:
email_doc -- 邮件文档
- 返回:
更新后的邮件文档
- async get_email(email_id: str) taolib.testing.email_service.models.email.EmailResponse#
获取邮件详情。
- async list_emails(status: taolib.testing.email_service.models.enums.EmailStatus | None = None, email_type: taolib.testing.email_service.models.enums.EmailType | None = None, skip: int = 0, limit: int = 100) list[taolib.testing.email_service.models.email.EmailResponse]#
查询邮件列表。
- class taolib.testing.email_service.QueueProcessor(queue: taolib.testing.email_service.queue.protocol.EmailQueueProtocol, email_repo: taolib.testing.email_service.repository.email_repo.EmailRepository, send_callback, poll_interval: float = 1.0, batch_size: int = 10)#
邮件队列处理器。
作为后台 asyncio.Task 运行,持续从队列取出邮件并发送。 参考 data_sync.services.scheduler.AsyncScheduler 模式。
- _queue#
- _email_repo#
- _send_callback#
- _poll_interval = 1.0#
- _batch_size = 10#
- _running = False#
- _task: asyncio.Task[None] | None = None#
- class taolib.testing.email_service.SubscriptionService(subscription_repo: taolib.testing.email_service.repository.subscription_repo.SubscriptionRepository)#
订阅管理服务。
- _repo#
- async get_or_create_subscription(email: str) taolib.testing.email_service.models.subscription.SubscriptionDocument#
获取或创建订阅记录。
如果邮箱没有订阅记录,则创建一个新的激活状态记录。
- 参数:
email -- 邮箱地址
- 返回:
订阅文档
- async unsubscribe(token: str, reason: str | None = None) taolib.testing.email_service.models.subscription.SubscriptionResponse#
处理退订请求。
- 参数:
token -- 退订令牌
reason -- 退订原因
- 返回:
更新后的订阅响应
- 抛出:
SubscriptionError -- 令牌无效或已退订
- async unsubscribe_by_email(email: str, reason: str | None = None) taolib.testing.email_service.models.subscription.SubscriptionResponse | None#
按邮箱退订(用于硬退信自动退订)。
- async resubscribe(email: str) taolib.testing.email_service.models.subscription.SubscriptionResponse#
重新订阅。
- 参数:
email -- 邮箱地址
- 返回:
更新后的订阅响应
- 抛出:
SubscriptionError -- 订阅记录不存在
- class taolib.testing.email_service.TemplateService(template_repo: taolib.testing.email_service.repository.template_repo.TemplateRepository, engine: taolib.testing.email_service.template.engine.TemplateEngine)#
模板管理服务。
- _repo#
- _engine#
- async create_template(data: taolib.testing.email_service.models.template.TemplateCreate) taolib.testing.email_service.models.template.TemplateResponse#
创建模板。
- async update_template(template_id: str, data: taolib.testing.email_service.models.template.TemplateUpdate) taolib.testing.email_service.models.template.TemplateResponse | None#
更新模板。
- async get_template(template_id: str) taolib.testing.email_service.models.template.TemplateResponse | None#
获取模板。
- async get_template_by_name(name: str) taolib.testing.email_service.models.template.TemplateResponse | None#
按名称获取模板。
- async list_templates(email_type: taolib.testing.email_service.models.enums.EmailType | None = None, is_active: bool | None = None, skip: int = 0, limit: int = 100) list[taolib.testing.email_service.models.template.TemplateResponse]#
查询模板列表。
- async render_template(template_id: str, variables: dict, email_type: taolib.testing.email_service.models.enums.EmailType = EmailType.TRANSACTIONAL, recipient_email: str | None = None, unsubscribe_token: str | None = None) taolib.testing.email_service.template.engine.RenderedEmail#
渲染模板。
- 参数:
template_id -- 模板 ID
variables -- 模板变量
email_type -- 邮件类型
recipient_email -- 收件人邮箱
unsubscribe_token -- 退订令牌
- 返回:
渲染后的邮件内容
- 抛出:
TemplateNotFoundError -- 模板不存在
- class taolib.testing.email_service.TrackingService(tracking_repo: taolib.testing.email_service.repository.tracking_repo.TrackingRepository, email_repo: taolib.testing.email_service.repository.email_repo.EmailRepository)#
追踪和分析服务。
- _tracking_repo#
- _email_repo#
- async record_event(email_id: str, event_type: taolib.testing.email_service.models.enums.TrackingEventType, recipient: str, provider: str | None = None, ip_address: str | None = None, user_agent: str | None = None, click_url: str | None = None, bounce_type: str | None = None, bounce_reason: str | None = None, raw_payload: dict | None = None) taolib.testing.email_service.models.tracking.TrackingEventResponse#
记录追踪事件。
同时更新关联的 EmailDocument 状态。
- async get_events_for_email(email_id: str) list[taolib.testing.email_service.models.tracking.TrackingEventResponse]#
获取邮件的所有追踪事件。
- async get_analytics(start: datetime.datetime, end: datetime.datetime) EmailAnalytics#
获取时间范围内的分析数据。
- async get_daily_stats(start: datetime.datetime, end: datetime.datetime) list[dict]#
获取按日统计数据。
- async _update_email_status(email_id: str, event_type: taolib.testing.email_service.models.enums.TrackingEventType, timestamp: datetime.datetime) None#
根据追踪事件更新邮件状态。
- class taolib.testing.email_service.RenderedEmail#
渲染后的邮件内容。
- class taolib.testing.email_service.TemplateEngine(unsubscribe_base_url: str = '')#
Jinja2 沙箱模板引擎。
使用 SandboxedEnvironment 防止模板注入攻击。 StrictUndefined 确保缺失变量会立即报错。
- _env: jinja2.Environment#
- _unsubscribe_base_url = ''#
- render(template_doc: taolib.testing.email_service.models.template.TemplateDocument, variables: dict, email_type: taolib.testing.email_service.models.enums.EmailType = EmailType.TRANSACTIONAL, recipient_email: str | None = None, unsubscribe_token: str | None = None) RenderedEmail#
渲染模板。
- 参数:
template_doc -- 模板文档
variables -- 模板变量
email_type -- 邮件类型
recipient_email -- 收件人邮箱(营销邮件需要)
unsubscribe_token -- 退订令牌(营销邮件需要)
- 返回:
渲染后的邮件内容
- 抛出:
TemplateRenderError -- 模板渲染失败