Skip to content

feat(backend): support smtp#11

Merged
sousuke0422 merged 9 commits into
mainfrom
feat/support-smtp
May 18, 2026
Merged

feat(backend): support smtp#11
sousuke0422 merged 9 commits into
mainfrom
feat/support-smtp

Conversation

@yupix
Copy link
Copy Markdown
Contributor

@yupix yupix commented May 18, 2026

Summary by CodeRabbit

  • New Features
    • SMTP経由のメール送信機能を追加。プレーンテキストとHTML本文に対応し、送信処理に30秒のタイムアウトを設定。
    • アプリ設定でSMTP接続情報(ホスト・ポート・ユーザー名・パスワード・送信元)を指定可能にし、環境サンプルを追加。
    • 起動時にSMTPクライアントを初期化し、初期化や送信失敗時に明確なエラーを返すように改善。

Review Change Stack

@yupix yupix linked an issue May 18, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

バックエンドに非同期SMTPクライアントをLettreで実装し、設定と依存を追加、AppStateへ組み込んで起動時に初期化する変更でメール送信を可能にしました。

変更

SMTP email送信機能統合

Layer / File(s) Summary
SMTP設定と依存関係
apps/backend/Cargo.toml, apps/backend/src/settings.rs, apps/backend/.env.example
LettreをCargo.tomlへ追加し、Settingssmtp_host/smtp_port/smtp_username/smtp_password/smtp_fromを追加、.env.exampleにサンプル変数を追記した。
SMTPクライアント実装
apps/backend/src/utils/mod.rs, apps/backend/src/utils/smtp.rs, apps/backend/src/utils/auth.rs
utils/smtp.rsSmtpClientを追加(AsyncSmtpTransport保持、new()でSTARTTLSトランスポートを構築、send_email()でplain/html切替マルチパート送信、30秒タイムアウト)。utils/mod.rsで公開し、auth.rsのimportを整形。
AppState統合
apps/backend/src/lib.rs
lib.rsSmtpClientをインポートし、AppStatesmtp_clientフィールドを追加して状態へ組み込んだ。
アプリケーション初期化
apps/backend/src/main.rs
main.rsで起動時にSmtpClient::newを呼び、初期化したクライアントをAppStateへ含めてrun(state)へ渡す処理を追加した。

推定コード レビュー労力

🎯 3 (Moderate) | ⏱️ ~20 minutes

うさぎがコードで穴を掘るよ🐇
Lett reの道を光らせるよ✉️
設定読み込んでクライアント生む
起動で箱にそっとしまう
走れ、電子の小さな手紙よ

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed プルリクエストのタイトル「feat(backend): support smtp」は、変更セット全体の主要な目的であるSMTP機能の追加を正確かつ簡潔に表現しており、チームメンバーが履歴を扫描する際に主要な変更内容を明確に理解できます。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • ✅ Generated successfully - (🔄 Check to regenerate)
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/support-smtp

Comment @coderabbitai help to get the list of available commands and usage tips.

@yupix yupix requested a review from sousuke0422 May 18, 2026 06:06
@yupix yupix self-assigned this May 18, 2026
@yupix yupix added priority/medium kind/新機能 New feature or request labels May 18, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/backend/src/settings.rs (1)

4-15: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

SettingsDebug 派生で SMTP パスワードが漏えいし得ます。

Line 4Debug 派生により、Line 14smtp_password がログ出力経路で平文露出するリスクがあります。機密情報を含む設定型では Debug を外すか、マスク実装にしてください。

修正案(最小)
-#[derive(Clone, Debug, Deserialize)]
+#[derive(Clone, Deserialize)]
 pub struct Settings {

As per coding guidelines, 「認証・認可、テナント境界、SQL の正しさ、エラーハンドリング、非同期処理の安全性を優先して確認してください。」

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/src/settings.rs` around lines 4 - 15, The Settings struct
derives Debug which can expose smtp_password in logs; remove Debug from
#[derive(...)] on Settings and add a custom impl std::fmt::Debug for Settings
that prints all fields but replaces smtp_password with a redacted value (e.g.,
"<redacted>" or masked length) so sensitive secrets are never emitted; update
any tests or usages that relied on the automatic Debug impl to use the new
masked Debug if needed and ensure the impl references Settings and smtp_password
by name.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/backend/src/utils/smtp.rs`:
- Around line 25-27: The doctest examples in apps/backend/src/utils/smtp.rs
attempt real network/async operations and cause test failures; update the
Rustdoc code fences for the SmtpClient::new example and the async
client.send_email example to use a non-executing attribute (e.g., add "ignore"
or "no_run") so they are not run as doctests, and for the async example ensure
it is marked ignored because it references an undefined variable `client` and
uses `.await` outside an async context (do not change logic, just mark both
examples to not execute).
- Around line 36-39: The AsyncSmtpTransport send path lacks an explicit timeout;
wrap the call to mailer.send(...).await inside tokio::time::timeout with a
sensible Duration (make it configurable or use a constant like smtp_timeout) and
handle the Err(elapsed) case by returning or mapping a timeout error from your
send_email function; update any code that constructs the mailer
(AsyncSmtpTransport::<Tokio1Executor>::starttls_relay) to keep using the same
mailer but enforce timeout only around the mailer.send(...) await, and ensure
the function returns a clear timeout-oriented error instead of hanging
indefinitely.

---

Outside diff comments:
In `@apps/backend/src/settings.rs`:
- Around line 4-15: The Settings struct derives Debug which can expose
smtp_password in logs; remove Debug from #[derive(...)] on Settings and add a
custom impl std::fmt::Debug for Settings that prints all fields but replaces
smtp_password with a redacted value (e.g., "<redacted>" or masked length) so
sensitive secrets are never emitted; update any tests or usages that relied on
the automatic Debug impl to use the new masked Debug if needed and ensure the
impl references Settings and smtp_password by name.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 08eb9857-814f-4937-917e-86a971c31bf7

📥 Commits

Reviewing files that changed from the base of the PR and between 7130872 and 384294b.

⛔ Files ignored due to path filters (1)
  • apps/backend/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • apps/backend/.env.example
  • apps/backend/Cargo.toml
  • apps/backend/src/lib.rs
  • apps/backend/src/main.rs
  • apps/backend/src/settings.rs
  • apps/backend/src/utils/mod.rs
  • apps/backend/src/utils/smtp.rs

Comment thread apps/backend/src/utils/smtp.rs Outdated
Comment thread apps/backend/src/utils/smtp.rs
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds SMTP-based email sending support to the backend (aligning with the request for an email feature, e.g. Issue #6), wiring a new SmtpClient into application state and introducing SMTP configuration via environment-driven settings.

Changes:

  • Added a new async SMTP utility (SmtpClient) capable of sending plain-text or multipart (text+HTML) emails.
  • Extended Settings and .env.example with SMTP configuration fields and instantiated the SMTP client during startup.
  • Added new dependencies (notably lettre) and updated the lockfile accordingly.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
apps/backend/src/utils/smtp.rs Introduces SmtpClient and email composition/sending logic (incl. timeout).
apps/backend/src/utils/mod.rs Exposes the new smtp utility module.
apps/backend/src/settings.rs Adds required SMTP-related settings fields loaded from environment.
apps/backend/src/main.rs Creates SmtpClient at startup and injects it into AppState.
apps/backend/src/lib.rs Extends AppState with an SMTP client handle.
apps/backend/Cargo.toml Adds email-related crates (lettre, lettre_email).
apps/backend/Cargo.lock Dependency graph update due to new crates.
apps/backend/.env.example Documents SMTP env vars required by the new settings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/backend/src/utils/smtp.rs Outdated
Comment on lines +100 to +103
let _ = timeout(Duration::from_secs(30), self.mailer.send(email))
.await
.map_err(|_| "SMTP send timeout")?;

Comment thread apps/backend/src/utils/smtp.rs Outdated
Comment on lines +1 to +4
use std::time::Duration;

/// SMTPクライアントを提供するモジュール

Comment thread apps/backend/Cargo.toml Outdated
Comment on lines +46 to +47
lettre = { version = "0.11", default-features = false, features = ["builder", "hostname", "smtp-transport","tokio1", "tokio1-rustls-tls"] }
lettre_email = "0.9" No newline at end of file
Comment thread apps/backend/src/settings.rs
Comment thread apps/backend/src/main.rs Outdated
settings.smtp_port,
&settings.smtp_username,
&settings.smtp_password,
)?;
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/backend/src/utils/smtp.rs`:
- Line 100: ハードコードされた30秒タイムアウトをモジュールレベルの定数に抽出してください:
timeout(Duration::from_secs(30), self.mailer.send(email)) の
Duration::from_secs(30) を例えば MAIL_SEND_TIMEOUT_SECS または MAIL_SEND_TIMEOUT
に置き換え、モジュール上部で定数として定義して参照するように修正してください(参照箇所: self.mailer.send(email) を囲む timeout
呼び出し)。
- Around line 100-102: The current call using `let _ =
timeout(Duration::from_secs(30), self.mailer.send(email)).await.map_err(|_|
"SMTP send timeout")?` discards the inner `Result<Response, SmtpError>` so real
SMTP errors are ignored; update the logic around `timeout`,
`self.mailer.send(email)` and the `await` to first handle the outer timeout
error, then inspect and propagate the inner `Result` from
`self.mailer.send(email)` (e.g., capture the outer result, then `map_err` or
`map` the inner `Result<Response, SmtpError>` into a proper error and `?` it) so
both timeout and SMTP send errors are returned instead of being dropped.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 6554ab81-e1e8-4b6a-8e14-59e7f4291306

📥 Commits

Reviewing files that changed from the base of the PR and between 384294b and 91e6573.

📒 Files selected for processing (1)
  • apps/backend/src/utils/smtp.rs

Comment thread apps/backend/src/utils/smtp.rs Outdated
Comment thread apps/backend/src/utils/smtp.rs Outdated
@yupix yupix changed the title Feat/support smtp feat(backend): support smtp May 18, 2026
@yupix yupix force-pushed the feat/support-smtp branch from 6f86cc2 to f3f7cc2 Compare May 18, 2026 07:13
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/backend/src/settings.rs`:
- Around line 11-15: The SMTP fields (smtp_host, smtp_port, smtp_username,
smtp_password, smtp_from) are currently required and cause load_settings() to
fail in environments without SMTP; change these fields to optional (e.g.,
Option<String>/Option<u16>) or gate them behind a feature flag so settings
deserialization succeeds when SMTP is unused, update load_settings() to
accept/migrate optional values, and adjust any code that references these fields
(e.g., mail-sending helper functions) to handle None (skip sending or return a
clear error) and to validate presence only when SMTP is actually enabled.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 06ecc781-d283-4b17-b771-0e47a5b2c093

📥 Commits

Reviewing files that changed from the base of the PR and between f3f7cc2 and 833e21f.

📒 Files selected for processing (1)
  • apps/backend/src/settings.rs

Comment on lines +11 to +15
pub smtp_host: String,
pub smtp_port: u16,
pub smtp_username: String,
pub smtp_password: String,
pub smtp_from: String,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

SMTP設定を全必須にすると既存環境で起動不能になる可能性があります。

Line 11-15 の smtp_* がすべて必須のため、未設定環境では load_settings() のデシリアライズで即失敗します。段階的導入を想定するなら Option 化または feature flag で無効化可能にして、メール未使用時は起動継続できる形にしてください。

As per coding guidelines 「Rust / Axum / SeaORM のバックエンドです。認証・認可、テナント境界、SQL の正しさ、エラーハンドリング、非同期処理の安全性を優先して確認してください。」。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/backend/src/settings.rs` around lines 11 - 15, The SMTP fields
(smtp_host, smtp_port, smtp_username, smtp_password, smtp_from) are currently
required and cause load_settings() to fail in environments without SMTP; change
these fields to optional (e.g., Option<String>/Option<u16>) or gate them behind
a feature flag so settings deserialization succeeds when SMTP is unused, update
load_settings() to accept/migrate optional values, and adjust any code that
references these fields (e.g., mail-sending helper functions) to handle None
(skip sending or return a clear error) and to validate presence only when SMTP
is actually enabled.

coderabbitai Bot added a commit that referenced this pull request May 18, 2026
Docstrings generation was requested by @yupix.

* #11 (comment)

The following files were modified:

* `apps/backend/src/main.rs`
* `apps/backend/src/settings.rs`
* `apps/backend/src/utils/smtp.rs`
@TeamBlackCrystal TeamBlackCrystal deleted a comment from coderabbitai Bot May 18, 2026
Copy link
Copy Markdown
Member

@sousuke0422 sousuke0422 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

よさそう

@sousuke0422 sousuke0422 merged commit 02bf9c5 into main May 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/新機能 New feature or request priority/medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

メール送信機能の実装

3 participants