メインコンテンツへ

メール

一言でいうと

メール連携は「受信メールをテーブルレコードとして取り込み、一覧・検索・スレッド表示できるようにする」機能です。IMAP をポーリングして受信し、SMTP で送信します。既読/フラグ/移動/削除といったユーザー操作は、まずローカルのレコードを更新し、対応する IMAP 操作は永続キューに積んで非同期に反映する local-first 設計です。

主要ドメイン概念

概念役割
UserMailboxユーザーごとの IMAP/SMTP 接続設定
InboundMailEvent / InboundMailMessage受信イベントと解析済みメッセージ
MailThreadResolverメッセージをスレッドにまとめる
MailOutboundOp既読/フラグ/移動/削除などローカル変更に対応する、IMAP側へ反映すべき操作の永続キューエントリ
MailPlacement受信メールをどのワークスペース/テーブルへ配置するかの解決結果

Backend 構造

  • api/controller/: MailMailboxController(接続設定・接続テスト・プロバイダ自動検出)、MailInboxControllerMailFolderControllerMailReadController/MailFlagController/MailMoveController/MailTrashController(既読・フラグ・移動・削除・復元・完全削除)、MailDraftController/MailSendController(下書き・送信)、MailImportController/MlMailboxImportController.eml/.mbox インポート)、TenantMailEventsController
  • domain/service/InboundMailIngestionService.kt: 受信メールを RecordService 経由でテーブルレコード化し、添付ファイルは StorageAwareDocumentService でドキュメントツリーへ保存。添付が抽出対象なら OrganizeJobCreator で AI 取込パイプラインに回す
  • domain/service/MailOutboundProjector.kt: ローカル変更 → 永続キュー enqueue を同一トランザクションで行う、outbound の唯一の入口(下記callout参照)
  • domain/service/MailOutboundOpQueueService.kt: キューの再試行ポリシー(bounded exponential backoff → 最終的に FAILED。ローカル変更自体はそのまま残り、次の reconcile が収束させる)
  • infrastructure/scheduler/MailImapPollingScheduler.kt / MailOutboundDrainScheduler.kt: 受信ポーリングと、outbound キューのドレイン(owner ごとに runAs(tenant, owner) で分離実行、1件の失敗が他をブロックしない)
  • infrastructure/listener/MailDeadlineExtractionListener.kt: 受信メールから AI で締切を抽出し、Google カレンダーへ反映する @TransactionalEventListener(AFTER_COMMIT) + @Async

Frontend 構造

  • composables/: useMailMailbox(接続設定)、useMailConnectFormuseMailReadStatus/useMailFlag/useMailMove/useMailTrash/useMailDelete(メッセージ操作)、useMailDraftsuseMailAttachmentPreview
  • components/: MailConnectForm.vue/MailConnectFields.vue/MailConnectPrompt.vue(接続設定UI)、MailConversationListItem.vue/MailMessagePanel.vue(スレッド表示)、MailComposeDialog.vueMailboxSettingsPanel.vueMailConversationPane.vue/MailOutputTableField.vue(テーブル上でのメールレコード表示)

他モジュールとの辺

  • table: 受信メールは RecordService 経由でレコードとして保存される。MailRecordAccessPort が owner の RLS context でアクセス制御する
  • organize: メール添付ファイルは AI 取込パイプライン(OCR → AI → 構造化レコード)に回せる
  • editor: 添付ファイルの実体は StorageAwareDocumentService を通してドキュメントツリーに保存される
  • calendar: MailDeadlineExtractionListener が受信メールから締切を抽出し、Google カレンダー連携(GoogleOAuthService)へ書き込む
  • display: ViewType.MAIL として受信箱をテーブル表示ビューの一種に描画できる

既読/フラグ/移動/削除といったメール状態変更は、必ず MailOutboundProjector を経由すること。MailImapPort を直接呼んではいけません。MailOutboundProjector は①ownerのRLS contextでの所有権チェック、②ローカルレコード更新、③IMAP操作の永続キューへの enqueue、の②③を同一トランザクションで行う契約になっており(「ローカル変更には必ず対応するキュー済み操作がある」を保証)、これを迂回すると local-first の整合性が壊れます。