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