335:class SendAttempt(Base, TimestampMixin):
336-    __tablename__ = "send_attempts"
337-    id = Column(Integer, primary_key=True)
338-    send_job_id = Column(Integer, ForeignKey("send_jobs.id", ondelete="CASCADE"), nullable=False, index=True)
339-    campaign_id = Column(Integer, ForeignKey("campaigns.id", ondelete="CASCADE"), nullable=False, index=True)
340-    gmail_account_id = Column(Integer, ForeignKey("gmail_accounts.id", ondelete="SET NULL"))
341-    recipient_email = Column(String(320), nullable=False)
342-    subject = Column(String(500), default="")
343-    template_name = Column(String(250), default="")
344-    attachment_names = Column(JSON, default=list)
345-    method = Column(String(20), default="api")  # api|smtp
346-    outcome = Column(String(30), nullable=False)  # submitted|accepted|temp_failed|perm_failed|skipped
347-    provider_response = Column(Text, default="")   # sanitized provider response
348-    message_id = Column(String(200), default="")
349-    thread_id = Column(String(200), default="")
350-    retry_no = Column(Integer, default=0)
351-    failure_reason = Column(Text, default="")
352-    error_class = Column(String(60), default="")  # temporary|permanent|auth|quota|unknown
353-
354-    send_job = relationship("SendJob")
355-
356-
357-class EmailEvent(Base, TimestampMixin):
