Email feature
This commit is contained in:
31
CPLIST/input/import_results_岐阜ロゲイニング2025_20250905_173618.csv
Normal file
31
CPLIST/input/import_results_岐阜ロゲイニング2025_20250905_173618.csv
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
チーム名,ゼッケン番号,カテゴリー,時間,オーナーメール,リーダー,メンバー数,メンバー一覧,参加登録状況,エントリーID,作成日時
|
||||||
|
いなりずし,1,一般-3時間,3.0時間,いなりずし_member_1@dummy.local,児玉優美(1976-12-13),5,優美(1976-12-13); 豊久(1973-11-23); 児玉優美(1976-12-13); 児玉豊久(1973-11-23); 田中広美(1975-10-31),完了,548,2025-09-05 07:46:39
|
||||||
|
Go to the peak!,2,一般-5時間,5.0時間,go_to_the_peak_member_1@dummy.local,柴山晋太郎(1974-12-14),3,柴山晋太郎(1974-12-14); 後藤克弘(1968-04-07); 二村修(1967-06-22),完了,549,2025-09-05 07:46:40
|
||||||
|
きみこうじ,3,一般-3時間,3.0時間,きみこうじ_member_1@dummy.local,齋藤貴美子(1980-07-06),2,齋藤貴美子(1980-07-06); 江口浩次(1968-04-19),完了,550,2025-09-05 07:46:40
|
||||||
|
ウエストサイド,4,一般-5時間,5.0時間,ウエストサイド_member_1@dummy.local,後藤睦子(1961-05-01),8,睦子(2000-01-01); マサトシ(2000-01-01); ショウコ(2000-01-01); ヨシミ(2000-01-01); 後藤睦子(1961-05-01); 後藤正寿(1959-07-23); 大坪照子(1958-11-11); 松村芳美(1964-04-28),完了,551,2025-09-05 07:46:40
|
||||||
|
ベル,5,一般-3時間,3.0時間,ベル_member_1@dummy.local,川村健一(1969-10-08),7,健一(2000-01-01); ショウジ(2000-01-01); チナミ(2000-01-01); 川村健一(1969-10-08); 曽我部知奈美(1973-12-17); 伊藤徳幸(1975-02-06); 筒井勝児(1976-05-31),完了,552,2025-09-05 07:46:40
|
||||||
|
ぐりと愉快な仲間たち,6,一般-3時間,3.0時間,ぐりと愉快な仲間たち_member_1@dummy.local,長屋香代子(1961-10-27),4,(1961-10-27); (1961-05-26); 長屋香代子(1961-10-27); 長屋宣宏(1961-05-26),完了,553,2025-09-05 07:46:40
|
||||||
|
坂本555,7,一般-5時間,5.0時間,坂本555_member_1@dummy.local,坂本正憲(1972-05-30),3,坂本正憲(1972-05-30); 坂本彩子(1976-03-29); 坂本瑠璃子(2003-08-23),完了,554,2025-09-05 07:46:40
|
||||||
|
M sisters with D,8,一般-5時間,5.0時間,m__sisters_with__d_member_1@dummy.local,前田貴代美(1973-01-15),2,前田貴代美(1973-01-15); 中濱智恵美(1969-06-16),完了,555,2025-09-05 07:46:41
|
||||||
|
さなっく,9,一般-5時間,5.0時間,さなっく_member_1@dummy.local,山田朋博(1971-04-23),2,山田朋博(1971-04-23); 眞田尚亮(1982-11-30),完了,556,2025-09-05 07:46:41
|
||||||
|
煮込みラーメン,10,一般-3時間,3.0時間,煮込みラーメン_member_1@dummy.local,西岡嵩倫(1999-01-05),4,(1999-01-05); (1971-02-02); 西岡嵩倫(1999-01-05); 西岡影忠(1971-02-02),完了,557,2025-09-05 07:46:41
|
||||||
|
サウナとビリヤニ,11,一般-3時間,3.0時間,サウナとビリヤニ_member_1@dummy.local,坂口祐生(1992-01-07),3,坂口祐生(1992-01-07); 近藤準(1987-01-25); 圓山大貴(1993-05-10),完了,558,2025-09-05 07:46:41
|
||||||
|
ひろ君と愉快な仲間たち,12,お試し・一般-3時間,3.0時間,ひろ君と愉快な仲間たち_member_1@dummy.local,山脇裕子(1984-01-26),5,山脇裕子(1984-01-26); 高橋美智子(1975-04-21); 樋口博久(1964-01-08); 雨宮功治(1962-05-25); 広瀬貴士(1978-08-17),完了,559,2025-09-05 07:46:41
|
||||||
|
山下和乃,13,女性ソロ-3時間,3.0時間,山下和乃_member_1@dummy.local,山下和乃(2004-04-26),1,山下和乃(2004-04-26),完了,560,2025-09-05 07:46:42
|
||||||
|
Best Wishes,14,女性ソロ-5時間,5.0時間,best_wishes_member_1@dummy.local,長谷川美貴(1973-05-06),2,美貴(1973-05-06); 長谷川美貴(1973-05-06),完了,561,2025-09-05 07:46:42
|
||||||
|
しーくん,15,男性ソロ-3時間,3.0時間,しーくん_member_1@dummy.local,水門茂(1962-12-24),2,茂(1962-12-24); 水門茂(1962-12-24),完了,562,2025-09-05 07:46:42
|
||||||
|
風呂の会,16,男性ソロ-5時間,5.0時間,風呂の会_member_1@dummy.local,浅井貴弘(1984-07-11),2,貴弘(2000-01-01); 浅井貴弘(1984-07-11),完了,563,2025-09-05 07:46:42
|
||||||
|
近藤隆,17,男性ソロ-5時間,5.0時間,近藤隆_member_1@dummy.local,近藤隆(1962-06-28),1,近藤隆(1962-06-28),完了,564,2025-09-05 07:46:42
|
||||||
|
日吉将大,18,男性ソロ-3時間,3.0時間,日吉将大_member_1@dummy.local,日吉将大(1995-09-14),2,(1995-09-14); 日吉将大(1995-09-14),完了,565,2025-09-05 07:46:42
|
||||||
|
東京OLクラブ,19,男性ソロ-3時間,3.0時間,東京olクラブ_member_1@dummy.local,阿部昌隆(1956-04-20),1,阿部昌隆(1956-04-20),完了,566,2025-09-05 07:46:42
|
||||||
|
Best Wishes,20,男性ソロ-5時間,5.0時間,best_wishes_member_1@dummy.local,長谷川美貴(1973-05-06),2,寿郎(1973-10-26); 長谷川美貴(1973-05-06),完了,567,2025-09-05 07:46:42
|
||||||
|
脇屋貴司,21,男性ソロ-5時間,5.0時間,脇屋貴司_member_1@dummy.local,脇屋貴司(1983-10-26),1,脇屋貴司(1983-10-26),完了,568,2025-09-05 07:46:42
|
||||||
|
うぱうぱアイランド,22,ファミリー-3時間,3.0時間,うぱうぱアイランド_member_1@dummy.local,伊藤由美子(1992-03-28),3,伊藤由美子(1992-03-28); 伊藤嘉仁(1993-08-25); 伊藤嘉利(2022-09-13),完了,569,2025-09-05 07:46:42
|
||||||
|
Team117,23,ファミリー-3時間,3.0時間,team117_member_1@dummy.local,佐々木孝好(1970-12-20),4,佐々木孝好(1970-12-20); 佐々木享子(1977-08-25); 佐々木実希(2012-01-21); 佐々木麻妃(2016-07-01),完了,570,2025-09-05 07:46:43
|
||||||
|
チームしぇいや,24,ファミリー-3時間,3.0時間,チームしぇいや_member_1@dummy.local,山本龍也(1976-03-14),6,聖也(2009-09-09); 輝也(2015-06-03); 龍也(1976-03-14); 山本龍也(1976-03-14); 山本聖也(2009-09-09); 山本輝也(2015-06-03),完了,571,2025-09-05 07:46:43
|
||||||
|
まゆちー,25,お試し-3時間,3.0時間,まゆちー_member_1@dummy.local,浅田舞子(1986-02-22),4,浅田舞子(1986-02-22); 浅田真結菜(2014-03-30); 森美紀(1988-03-06); 森千晴(2017-08-04),完了,572,2025-09-05 07:56:33
|
||||||
|
ガンバルゾー,26,お試し-3時間,3.0時間,ガンバルゾー_member_1@dummy.local,森祐貴(1985-09-26),4,森祐貴(1985-09-26); 浅田直之(1987-12-12); 浅田晃汰(2014-01-06); 森光喜(2015-04-22),完了,573,2025-09-05 07:56:33
|
||||||
|
ランエンジョン!,27,お試し-5時間,5.0時間,ランエンジョン!_member_1@dummy.local,河合賢次(1972-12-14),2,河合賢次(1972-12-14); 中野真樹(1973-01-23),完了,574,2025-09-05 07:56:33
|
||||||
|
fun!fun!うごchan,28,お試し-5時間,5.0時間,funfunうごchan_member_1@dummy.local,早川宏美(1975-06-15),1,早川宏美(1975-06-15),完了,575,2025-09-05 08:36:17
|
||||||
|
ポエドリ,29,お試し-5時間,5.0時間,ポエドリ_member_1@dummy.local,高木俊裕(1984-03-09),1,高木俊裕(1984-03-09),完了,576,2025-09-05 08:36:18
|
||||||
|
前川一彦,30,男性ソロ-5時間,5.0時間,前川一彦_member_1@dummy.local,前川一彦(1990-01-01),1,前川一彦(1990-01-01),完了,577,2025-09-05 08:36:18
|
||||||
|
2
CPLIST/input/team_mail.csv
Normal file
2
CPLIST/input/team_mail.csv
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1
|
||||||
|
2,5,一般,ウエストサイド,hannivalscipio@gmail.com,ka9749,090-4790-9749,宮田 明
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
部門別数,時間,部門,"チーム名
|
部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,,
|
||||||
",メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,,
|
|
||||||
2,5,お試し・ファミリー,fun!fun!うごchan,fulayota333@gmail.com,ha7384,090-6599-7384,早川宏美,1975/6/15,,,,,,,,,,,,,,
|
2,5,お試し・ファミリー,fun!fun!うごchan,fulayota333@gmail.com,ha7384,090-6599-7384,早川宏美,1975/6/15,,,,,,,,,,,,,,
|
||||||
1,5,お試し・ファミリー,ポエドリ,takagitoshihiro8@yahoo.co.jp,ta4245,090-5866-4245,高木俊裕,1984/03/09,,,,,,,,,,,,,,
|
1,5,お試し・ファミリー,ポエドリ,takagitoshihiro8@yahoo.co.jp,ta4245,090-5866-4245,高木俊裕,1984/03/09,,,,,,,,,,,,,,
|
||||||
7,5,男性ソロ,前川一彦,yoshino-chuo@docomo.ne.jp,ma2351,090-1074-2351,前川一彦,1990/1/1,,,,,,,,,,,,,,
|
7,5,男性ソロ,前川一彦,yoshino-chuo@docomo.ne.jp,ma2351,090-1074-2351,前川一彦,1990/1/1,,,,,,,,,,,,,,
|
||||||
|
243
EMAIL_SENDING_MANUAL.md
Normal file
243
EMAIL_SENDING_MANUAL.md
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
# チームメール送信システム操作マニュアル
|
||||||
|
|
||||||
|
## 概要
|
||||||
|
このシステムは、ロゲイニング大会の参加チームに対して、パスワードやイベント情報を含むメールを一括送信するためのDjango管理コマンドです。
|
||||||
|
|
||||||
|
## 前提条件
|
||||||
|
|
||||||
|
### 必要な環境
|
||||||
|
- Docker Compose環境が稼働していること
|
||||||
|
- PostgreSQLデータベースが接続されていること
|
||||||
|
- SMTPサーバー設定が完了していること(Outlook: smtp.outlook.com:587)
|
||||||
|
|
||||||
|
### 必要なファイル
|
||||||
|
1. **CSVファイル**: チーム情報を含むデータファイル
|
||||||
|
2. **メールテンプレートファイル**:
|
||||||
|
- `/templates/emails/team_registration_subject.txt` (件名テンプレート)
|
||||||
|
- `/templates/emails/team_registration_body.txt` (本文テンプレート)
|
||||||
|
|
||||||
|
## CSVファイル形式
|
||||||
|
|
||||||
|
### ファイル配置場所
|
||||||
|
```
|
||||||
|
CPLIST/input/team_mail.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSVファイルの形式
|
||||||
|
```csv
|
||||||
|
team_name,email,password,category,duration,leader_name,phone_number,member_names
|
||||||
|
チーム名,メールアドレス,パスワード,部門,時間,代表者名,電話番号,メンバー名
|
||||||
|
```
|
||||||
|
|
||||||
|
### 例
|
||||||
|
```csv
|
||||||
|
team_name,email,password,category,duration,leader_name,phone_number,member_names
|
||||||
|
ウエストサイド,hannivalscipio@gmail.com,west123,一般,3,田中太郎,090-1234-5678,田中太郎・佐藤花子
|
||||||
|
```
|
||||||
|
|
||||||
|
## メールテンプレート
|
||||||
|
|
||||||
|
### 件名テンプレート (`/templates/emails/team_registration_subject.txt`)
|
||||||
|
```
|
||||||
|
【岐阜ロゲ in 大垣】チーム「{{ team_name }}」パスワードのご連絡
|
||||||
|
```
|
||||||
|
|
||||||
|
### 本文テンプレート (`/templates/emails/team_registration_body.txt`)
|
||||||
|
```
|
||||||
|
{{ team_name }} 代表者 {{leader_name}} 様
|
||||||
|
|
||||||
|
岐阜ロゲ in 大垣 へのご参加ありがとうございます。
|
||||||
|
|
||||||
|
ご連絡が大変遅くなり、申し訳ございません。
|
||||||
|
|
||||||
|
以下の内容でパスワードをお送りいたしますので、よろしくお願い申し上げます。
|
||||||
|
|
||||||
|
■ チーム情報
|
||||||
|
|
||||||
|
チーム名: {{ team_name }}
|
||||||
|
部門: {{ category }}({{ duration }}時間)
|
||||||
|
|
||||||
|
ユーザー名: {{ email }}
|
||||||
|
パスワード: {{ password }}
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
岐阜ロゲ in 大垣
|
||||||
|
運営:NPO 岐阜aiネットワーク
|
||||||
|
```
|
||||||
|
|
||||||
|
### 利用可能な変数
|
||||||
|
- `{{ team_name }}` - チーム名
|
||||||
|
- `{{ email }}` - メールアドレス
|
||||||
|
- `{{ password }}` - パスワード
|
||||||
|
- `{{ category }}` - 部門
|
||||||
|
- `{{ duration }}` - 時間
|
||||||
|
- `{{ leader_name }}` - 代表者名
|
||||||
|
- `{{ phone_number }}` - 電話番号
|
||||||
|
- `{{ member_names }}` - メンバー名
|
||||||
|
|
||||||
|
## 操作手順
|
||||||
|
|
||||||
|
### 1. 事前準備
|
||||||
|
1. CSVファイルを `CPLIST/input/team_mail.csv` に配置
|
||||||
|
2. メールテンプレートファイルを確認・編集
|
||||||
|
3. Docker環境が起動していることを確認
|
||||||
|
|
||||||
|
### 2. ドライラン(テスト実行)
|
||||||
|
実際にメールを送信する前に、テスト実行を行います:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/rogaining_srv
|
||||||
|
docker compose exec app python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv' --dry_run
|
||||||
|
```
|
||||||
|
|
||||||
|
**ドライランの確認項目:**
|
||||||
|
- CSVファイルが正常に読み込まれるか
|
||||||
|
- テンプレートが正しく適用されるか
|
||||||
|
- 送信対象の件数が正しいか
|
||||||
|
- メールの件名・本文のプレビューが正しいか
|
||||||
|
|
||||||
|
### 3. 実際のメール送信
|
||||||
|
ドライランで問題がないことを確認後、実際の送信を行います:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/rogaining_srv
|
||||||
|
docker compose exec app python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 送信結果の確認
|
||||||
|
コマンド実行後、以下の情報が表示されます:
|
||||||
|
- 処理行数
|
||||||
|
- メール送信数
|
||||||
|
- エラーがあった場合のエラー内容
|
||||||
|
|
||||||
|
## コマンドオプション
|
||||||
|
|
||||||
|
### 基本コマンド
|
||||||
|
```bash
|
||||||
|
python manage.py send_team_emails --csv_file='<CSVファイルパス>'
|
||||||
|
```
|
||||||
|
|
||||||
|
### オプション一覧
|
||||||
|
- `--csv_file`: CSVファイルのパス(必須)
|
||||||
|
- `--dry_run`: ドライラン(テスト実行)モード
|
||||||
|
- `--delay`: メール送信間隔(秒)デフォルト: 1秒
|
||||||
|
|
||||||
|
### 使用例
|
||||||
|
```bash
|
||||||
|
# ドライランモード
|
||||||
|
python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv' --dry_run
|
||||||
|
|
||||||
|
# 実際の送信
|
||||||
|
python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv'
|
||||||
|
|
||||||
|
# 送信間隔を3秒に設定
|
||||||
|
python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv' --delay=3
|
||||||
|
```
|
||||||
|
|
||||||
|
## エラー対処法
|
||||||
|
|
||||||
|
### よくあるエラーと対処法
|
||||||
|
|
||||||
|
#### 1. CSVファイルが見つからない
|
||||||
|
```
|
||||||
|
CommandError: CSVファイルが見つかりません: CPLIST/input/team_mail.csv
|
||||||
|
```
|
||||||
|
**対処法:**
|
||||||
|
- ファイルパスを確認
|
||||||
|
- ファイル名のスペルミスをチェック
|
||||||
|
- ファイルが存在することを `ls -la CPLIST/input/` で確認
|
||||||
|
|
||||||
|
#### 2. テンプレートファイルが見つからない
|
||||||
|
```
|
||||||
|
TemplateDoesNotExist: emails/team_registration_subject.txt
|
||||||
|
```
|
||||||
|
**対処法:**
|
||||||
|
- テンプレートファイルが正しい場所に配置されているか確認
|
||||||
|
- ファイル名が正しいかチェック
|
||||||
|
- Docker容器を再起動: `docker compose restart app`
|
||||||
|
|
||||||
|
#### 3. SMTP接続エラー
|
||||||
|
```
|
||||||
|
SMTPException: SMTP Auth failure
|
||||||
|
```
|
||||||
|
**対処法:**
|
||||||
|
- メールサーバー設定を確認
|
||||||
|
- 認証情報(ユーザー名・パスワード)を確認
|
||||||
|
- ネットワーク接続を確認
|
||||||
|
|
||||||
|
#### 4. CSV読み込みエラー
|
||||||
|
**対処法:**
|
||||||
|
- CSVファイルの文字エンコーディング(UTF-8 BOM)を確認
|
||||||
|
- CSVヘッダーが正しいか確認
|
||||||
|
- 必須フィールドが欠けていないかチェック
|
||||||
|
|
||||||
|
## セキュリティ注意事項
|
||||||
|
|
||||||
|
1. **パスワード情報の取り扱い**
|
||||||
|
- CSVファイルには機密情報が含まれるため、適切なアクセス権限を設定
|
||||||
|
- 送信完了後はCSVファイルを安全な場所に移動またはバックアップ
|
||||||
|
|
||||||
|
2. **メール送信記録**
|
||||||
|
- 送信ログを保存し、送信状況を記録
|
||||||
|
- 重複送信を避けるため、送信済みチームを管理
|
||||||
|
|
||||||
|
3. **レート制限**
|
||||||
|
- 大量送信時はレート制限を考慮し、適切な間隔を設定
|
||||||
|
- SMTPサーバーの制限を確認
|
||||||
|
|
||||||
|
## トラブルシューティング
|
||||||
|
|
||||||
|
### Docker関連
|
||||||
|
```bash
|
||||||
|
# コンテナの状態確認
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# コンテナの再起動
|
||||||
|
docker compose restart app
|
||||||
|
|
||||||
|
# ログの確認
|
||||||
|
docker compose logs app
|
||||||
|
```
|
||||||
|
|
||||||
|
### データベース接続確認
|
||||||
|
```bash
|
||||||
|
# データベース接続テスト
|
||||||
|
docker compose exec app python manage.py dbshell
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSVファイル確認
|
||||||
|
```bash
|
||||||
|
# ファイル存在確認
|
||||||
|
ls -la CPLIST/input/
|
||||||
|
|
||||||
|
# ファイル内容確認
|
||||||
|
head -5 CPLIST/input/team_mail.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
## 運用Tips
|
||||||
|
|
||||||
|
1. **バッチ送信**
|
||||||
|
- 大量のメール送信時は、CSVファイルを分割して複数回に分けて送信
|
||||||
|
- 送信間隔を適切に設定してサーバー負荷を軽減
|
||||||
|
|
||||||
|
2. **テスト環境での確認**
|
||||||
|
- 本番送信前に、テスト用メールアドレスでの動作確認を推奨
|
||||||
|
- ドライランを必ず実行
|
||||||
|
|
||||||
|
3. **バックアップ**
|
||||||
|
- 送信前にCSVファイルとテンプレートファイルをバックアップ
|
||||||
|
- 送信ログを保存
|
||||||
|
|
||||||
|
## 更新履歴
|
||||||
|
|
||||||
|
- 2025年9月5日: 初版作成
|
||||||
|
- 基本的なメール送信機能
|
||||||
|
- Django テンプレートシステム統合
|
||||||
|
- Outlook SMTP設定対応
|
||||||
|
|
||||||
|
## 連絡先
|
||||||
|
|
||||||
|
システムに関する問い合わせ:
|
||||||
|
- 運営:NPO 岐阜aiネットワーク
|
||||||
|
- メール:rogaining@gifuai.net
|
||||||
@ -275,7 +275,7 @@ EMAIL_HOST = 'smtp.outlook.com'
|
|||||||
EMAIL_PORT = 587
|
EMAIL_PORT = 587
|
||||||
EMAIL_USE_TLS = True
|
EMAIL_USE_TLS = True
|
||||||
EMAIL_HOST_USER = 'rogaining@gifuai.net'
|
EMAIL_HOST_USER = 'rogaining@gifuai.net'
|
||||||
EMAIL_HOST_PASSWORD = 'ctcpy9823"x~'
|
EMAIL_HOST_PASSWORD = 'gifuainetwork@123'
|
||||||
DEFAULT_FROM_EMAIL = 'rogaining@gifuai.net'
|
DEFAULT_FROM_EMAIL = 'rogaining@gifuai.net'
|
||||||
|
|
||||||
APP_DOWNLOAD_LINK = 'https://apps.apple.com/jp/app/%E5%B2%90%E9%98%9C%E3%83%8A%E3%83%93/id6444221792'
|
APP_DOWNLOAD_LINK = 'https://apps.apple.com/jp/app/%E5%B2%90%E9%98%9C%E3%83%8A%E3%83%93/id6444221792'
|
||||||
|
|||||||
282
rog/management/commands/send_team_emails.py
Normal file
282
rog/management/commands/send_team_emails.py
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
"""
|
||||||
|
CSVファイルからチーム情報を読み込んでメール送信するDjango管理コマンド
|
||||||
|
Outlook SMTP (rogaining@gifuai.net) での送信に対応
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
# ドライラン(実際には送信しない)
|
||||||
|
docker compose exec app python manage.py send_team_emails --csv_file="CPLIST/input/team_mail.csv" --dry_run
|
||||||
|
|
||||||
|
# 実際のメール送信(送信間隔1秒)
|
||||||
|
docker compose exec app python manage.py send_team_emails --csv_file="CPLIST/input/team_mail.csv"
|
||||||
|
|
||||||
|
# カスタム送信間隔(3秒間隔)
|
||||||
|
docker compose exec app python manage.py send_team_emails --csv_file="CPLIST/input/team_mail.csv" --delay=3
|
||||||
|
|
||||||
|
Author: システム開発チーム
|
||||||
|
Date: 2025-09-05
|
||||||
|
"""
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.core.mail import send_mail
|
||||||
|
from django.conf import settings
|
||||||
|
from django.template.loader import render_to_string
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'CSVファイルからチーム情報を読み込んでOutlook SMTPでメール送信'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--csv_file',
|
||||||
|
type=str,
|
||||||
|
required=True,
|
||||||
|
help='CSVファイルのパス (例: CPLIST/input/team_mail.csv)'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--dry_run',
|
||||||
|
action='store_true',
|
||||||
|
help='ドライラン(実際にはメール送信しない)'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--delay',
|
||||||
|
type=int,
|
||||||
|
default=1,
|
||||||
|
help='メール送信間隔(秒)デフォルト: 1秒'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--test_email',
|
||||||
|
type=str,
|
||||||
|
help='テスト用メールアドレス(指定した場合、全てのメールをこのアドレスに送信)'
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
csv_file = options['csv_file']
|
||||||
|
dry_run = options['dry_run']
|
||||||
|
delay = options['delay']
|
||||||
|
test_email = options.get('test_email')
|
||||||
|
|
||||||
|
mode = '[DRY RUN] ' if dry_run else ''
|
||||||
|
self.stdout.write(f'{mode}CSVメール送信開始: csv_file={csv_file}')
|
||||||
|
|
||||||
|
if test_email:
|
||||||
|
self.stdout.write(f'🧪 テストモード: 全メールを {test_email} に送信')
|
||||||
|
|
||||||
|
# CSVファイル存在確認
|
||||||
|
if not os.path.exists(csv_file):
|
||||||
|
raise CommandError(f'CSVファイルが見つかりません: {csv_file}')
|
||||||
|
|
||||||
|
# SMTP設定確認
|
||||||
|
self.verify_email_settings()
|
||||||
|
|
||||||
|
# 統計情報
|
||||||
|
stats = {
|
||||||
|
'total_rows': 0,
|
||||||
|
'emails_sent': 0,
|
||||||
|
'errors': []
|
||||||
|
}
|
||||||
|
|
||||||
|
# CSVファイル読み込み・メール送信
|
||||||
|
try:
|
||||||
|
with open(csv_file, 'r', encoding='utf-8-sig') as f:
|
||||||
|
reader = csv.DictReader(f)
|
||||||
|
|
||||||
|
for row_num, row in enumerate(reader, start=2):
|
||||||
|
stats['total_rows'] += 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
# CSVデータ取得
|
||||||
|
team_data = self.extract_team_data(row)
|
||||||
|
|
||||||
|
# メール内容生成
|
||||||
|
email_content = self.generate_email_content(team_data)
|
||||||
|
subject = email_content['subject']
|
||||||
|
body = email_content['body']
|
||||||
|
|
||||||
|
# 送信先決定(テストモードならtest_emailに)
|
||||||
|
recipient = test_email if test_email else team_data['email']
|
||||||
|
|
||||||
|
self.stdout.write(f'{mode}行 {row_num}: {team_data["team_name"]} → {recipient}')
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
self.show_email_preview(subject, body)
|
||||||
|
else:
|
||||||
|
# 実際のメール送信
|
||||||
|
self.send_email(subject, body, recipient, team_data)
|
||||||
|
self.stdout.write(f' ✅ メール送信完了')
|
||||||
|
|
||||||
|
# 送信間隔
|
||||||
|
if delay > 0:
|
||||||
|
time.sleep(delay)
|
||||||
|
|
||||||
|
stats['emails_sent'] += 1
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = f'行 {row_num}: {str(e)}'
|
||||||
|
stats['errors'].append(error_msg)
|
||||||
|
self.stdout.write(self.style.ERROR(error_msg))
|
||||||
|
continue
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise CommandError(f'CSVファイル読み込みエラー: {str(e)}')
|
||||||
|
|
||||||
|
# 結果レポート
|
||||||
|
self.print_stats(stats, dry_run)
|
||||||
|
|
||||||
|
def verify_email_settings(self):
|
||||||
|
"""SMTP設定確認"""
|
||||||
|
required_settings = [
|
||||||
|
'EMAIL_HOST', 'EMAIL_PORT', 'EMAIL_HOST_USER',
|
||||||
|
'EMAIL_HOST_PASSWORD', 'DEFAULT_FROM_EMAIL'
|
||||||
|
]
|
||||||
|
|
||||||
|
for setting in required_settings:
|
||||||
|
if not hasattr(settings, setting) or not getattr(settings, setting):
|
||||||
|
raise CommandError(f'メール設定が不完全です: {setting}')
|
||||||
|
|
||||||
|
self.stdout.write(f'📧 SMTP設定確認完了: {settings.EMAIL_HOST}:{settings.EMAIL_PORT}')
|
||||||
|
self.stdout.write(f'📧 送信者: {settings.DEFAULT_FROM_EMAIL}')
|
||||||
|
|
||||||
|
def extract_team_data(self, row):
|
||||||
|
"""CSVデータからチーム情報を抽出"""
|
||||||
|
team_data = {
|
||||||
|
'team_name': row.get('チーム名', '').strip(),
|
||||||
|
'email': row.get('メール', '').strip(),
|
||||||
|
'category': row.get('部門', '').strip(),
|
||||||
|
'duration': row.get('時間', '').strip(),
|
||||||
|
'member_name': row.get('氏名1', '').strip(),
|
||||||
|
'phone': row.get('電話', '').strip(),
|
||||||
|
}
|
||||||
|
|
||||||
|
# 必須項目チェック
|
||||||
|
if not team_data['team_name']:
|
||||||
|
raise ValueError('チーム名が必要です')
|
||||||
|
if not team_data['email']:
|
||||||
|
raise ValueError('メールアドレスが必要です')
|
||||||
|
|
||||||
|
return team_data
|
||||||
|
|
||||||
|
def generate_email_content(self, team_data):
|
||||||
|
"""メール内容生成(外部テンプレートファイル使用)"""
|
||||||
|
# テンプレートファイルから件名を読み込み
|
||||||
|
subject = render_to_string(
|
||||||
|
'emails/team_registration_subject.txt',
|
||||||
|
team_data
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
# テンプレートファイルから本文を読み込み
|
||||||
|
body = render_to_string(
|
||||||
|
'emails/team_registration_body.txt',
|
||||||
|
team_data
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'subject': subject,
|
||||||
|
'body': body
|
||||||
|
}
|
||||||
|
|
||||||
|
def show_email_preview(self, subject, body):
|
||||||
|
"""メールプレビュー表示(ドライラン用)"""
|
||||||
|
self.stdout.write(f' 件名: {subject}')
|
||||||
|
self.stdout.write(f' 本文プレビュー: {body[:100]}...')
|
||||||
|
|
||||||
|
def send_email(self, subject, body, recipient, team_data):
|
||||||
|
"""実際のメール送信"""
|
||||||
|
try:
|
||||||
|
send_mail(
|
||||||
|
subject=subject,
|
||||||
|
message=body,
|
||||||
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
||||||
|
recipient_list=[recipient],
|
||||||
|
fail_silently=False
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f'メール送信エラー ({recipient}): {str(e)}')
|
||||||
|
|
||||||
|
def print_stats(self, stats, dry_run):
|
||||||
|
"""統計情報の表示"""
|
||||||
|
mode = '[DRY RUN] ' if dry_run else ''
|
||||||
|
|
||||||
|
self.stdout.write(self.style.SUCCESS('\n' + '='*50))
|
||||||
|
self.stdout.write(self.style.SUCCESS(f'{mode}メール送信結果'))
|
||||||
|
self.stdout.write(self.style.SUCCESS('='*50))
|
||||||
|
self.stdout.write(f'処理行数: {stats["total_rows"]}')
|
||||||
|
self.stdout.write(f'メール送信数: {stats["emails_sent"]}')
|
||||||
|
|
||||||
|
if stats['errors']:
|
||||||
|
self.stdout.write(f'エラー数: {len(stats["errors"])}')
|
||||||
|
for error in stats['errors']:
|
||||||
|
self.stdout.write(f' {error}')
|
||||||
|
|
||||||
|
if not dry_run:
|
||||||
|
self.stdout.write(self.style.SUCCESS('\nメール送信完了!'))
|
||||||
|
else:
|
||||||
|
self.stdout.write(self.style.WARNING('\n※ ドライランのため、実際のメール送信は行われていません'))
|
||||||
|
|
||||||
|
def send_email_to_team(self, row, template_content, template_name, row_num, stats):
|
||||||
|
"""実際のメール送信"""
|
||||||
|
team_name = row.get('チーム名', '').strip()
|
||||||
|
email = row.get('メール', '').strip()
|
||||||
|
category = row.get('部門', '').strip()
|
||||||
|
duration = row.get('時間', '').strip()
|
||||||
|
leader_name = row.get('氏名1', '').strip()
|
||||||
|
phone = row.get('電話番号', '').strip()
|
||||||
|
|
||||||
|
if not email:
|
||||||
|
raise ValueError('メールアドレスが必要です')
|
||||||
|
if not team_name:
|
||||||
|
raise ValueError('チーム名が必要です')
|
||||||
|
|
||||||
|
# テンプレート処理
|
||||||
|
context_data = {
|
||||||
|
'event_name': '岐阜ロゲイニング2025',
|
||||||
|
'team_name': team_name,
|
||||||
|
'category': category,
|
||||||
|
'duration': duration,
|
||||||
|
'leader_name': leader_name,
|
||||||
|
'email': email,
|
||||||
|
'phone': phone,
|
||||||
|
'password': row.get('パスワード', '').strip()
|
||||||
|
}
|
||||||
|
|
||||||
|
# テンプレートファイルから件名・本文を生成
|
||||||
|
subject = render_to_string('emails/team_registration_subject.txt', context_data).strip()
|
||||||
|
body = render_to_string('emails/team_registration_body.txt', context_data).strip()
|
||||||
|
|
||||||
|
# メール送信
|
||||||
|
try:
|
||||||
|
send_mail(
|
||||||
|
subject=subject,
|
||||||
|
message=body,
|
||||||
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
||||||
|
recipient_list=[email],
|
||||||
|
fail_silently=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.stdout.write(f'行 {row_num}: メール送信完了 {team_name} ({email})')
|
||||||
|
stats['emails_sent'] += 1
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f'メール送信エラー: {str(e)}')
|
||||||
|
|
||||||
|
def print_stats(self, stats, dry_run):
|
||||||
|
"""統計情報の表示"""
|
||||||
|
mode = '[DRY RUN] ' if dry_run else ''
|
||||||
|
|
||||||
|
self.stdout.write(self.style.SUCCESS('\n' + '='*50))
|
||||||
|
self.stdout.write(self.style.SUCCESS(f'{mode}メール送信結果'))
|
||||||
|
self.stdout.write(self.style.SUCCESS('='*50))
|
||||||
|
self.stdout.write(f'処理行数: {stats["total_rows"]}')
|
||||||
|
self.stdout.write(f'メール送信数: {stats["emails_sent"]}')
|
||||||
|
|
||||||
|
if stats['errors']:
|
||||||
|
self.stdout.write(f'\nエラー数: {len(stats["errors"])}')
|
||||||
|
for error in stats['errors']:
|
||||||
|
self.stdout.write(f' {error}')
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
self.stdout.write(self.style.WARNING('\n※ ドライランのため、実際にはメールは送信されていません'))
|
||||||
|
else:
|
||||||
|
self.stdout.write(self.style.SUCCESS('\nメール送信完了!'))
|
||||||
21
templates/emails/team_registration_body.txt
Normal file
21
templates/emails/team_registration_body.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{{ team_name }} 代表者 {{leader_name}} 様
|
||||||
|
|
||||||
|
岐阜ロゲ in 大垣 へのご参加ありがとうございます。
|
||||||
|
|
||||||
|
ご連絡が大変遅くなり、申し訳ございません。
|
||||||
|
|
||||||
|
以下の内容でパスワードをお送りいたしますので、よろしくお願い申し上げます。
|
||||||
|
|
||||||
|
■ チーム情報
|
||||||
|
|
||||||
|
チーム名: {{ team_name }}
|
||||||
|
部門: {{ category }}({{ duration }}時間)
|
||||||
|
|
||||||
|
ユーザー名: {{ email }}
|
||||||
|
パスワード: {{ password }}
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
岐阜ロゲ in 大垣
|
||||||
|
運営:NPO 岐阜aiネットワーク
|
||||||
|
Email: info@gifuai.net
|
||||||
1
templates/emails/team_registration_subject.txt
Normal file
1
templates/emails/team_registration_subject.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
【岐阜ロゲ in 大垣】チーム「{{ team_name }}」パスワードのご連絡
|
||||||
3
test_email.csv
Normal file
3
test_email.csv
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
チーム名,部門,時間,氏名1,メール,電話番号
|
||||||
|
テストチーム1,一般,4,テスト 太郎,test@example.com,090-1234-5678
|
||||||
|
テストチーム2,ファミリー,3,テスト 花子,test2@example.com,080-9876-5432
|
||||||
|
243
メール送信マニュアル.md
Normal file
243
メール送信マニュアル.md
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
# チームメール送信システム操作マニュアル
|
||||||
|
|
||||||
|
## 概要
|
||||||
|
このシステムは、ロゲイニング大会の参加チームに対して、パスワードやイベント情報を含むメールを一括送信するためのDjango管理コマンドです。
|
||||||
|
|
||||||
|
## 前提条件
|
||||||
|
|
||||||
|
### 必要な環境
|
||||||
|
- Docker Compose環境が稼働していること
|
||||||
|
- PostgreSQLデータベースが接続されていること
|
||||||
|
- SMTPサーバー設定が完了していること(Outlook: smtp.outlook.com:587)
|
||||||
|
|
||||||
|
### 必要なファイル
|
||||||
|
1. **CSVファイル**: チーム情報を含むデータファイル
|
||||||
|
2. **メールテンプレートファイル**:
|
||||||
|
- `/templates/emails/team_registration_subject.txt` (件名テンプレート)
|
||||||
|
- `/templates/emails/team_registration_body.txt` (本文テンプレート)
|
||||||
|
|
||||||
|
## CSVファイル形式
|
||||||
|
|
||||||
|
### ファイル配置場所
|
||||||
|
```
|
||||||
|
CPLIST/input/team_mail.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSVファイルの形式
|
||||||
|
```csv
|
||||||
|
team_name,email,password,category,duration,leader_name,phone_number,member_names
|
||||||
|
チーム名,メールアドレス,パスワード,部門,時間,代表者名,電話番号,メンバー名
|
||||||
|
```
|
||||||
|
|
||||||
|
### 例
|
||||||
|
```csv
|
||||||
|
team_name,email,password,category,duration,leader_name,phone_number,member_names
|
||||||
|
ウエストサイド,hannivalscipio@gmail.com,west123,一般,3,田中太郎,090-1234-5678,田中太郎・佐藤花子
|
||||||
|
```
|
||||||
|
|
||||||
|
## メールテンプレート
|
||||||
|
|
||||||
|
### 件名テンプレート (`/templates/emails/team_registration_subject.txt`)
|
||||||
|
```
|
||||||
|
【岐阜ロゲ in 大垣】チーム「{{ team_name }}」パスワードのご連絡
|
||||||
|
```
|
||||||
|
|
||||||
|
### 本文テンプレート (`/templates/emails/team_registration_body.txt`)
|
||||||
|
```
|
||||||
|
{{ team_name }} 代表者 {{leader_name}} 様
|
||||||
|
|
||||||
|
岐阜ロゲ in 大垣 へのご参加ありがとうございます。
|
||||||
|
|
||||||
|
ご連絡が大変遅くなり、申し訳ございません。
|
||||||
|
|
||||||
|
以下の内容でパスワードをお送りいたしますので、よろしくお願い申し上げます。
|
||||||
|
|
||||||
|
■ チーム情報
|
||||||
|
|
||||||
|
チーム名: {{ team_name }}
|
||||||
|
部門: {{ category }}({{ duration }}時間)
|
||||||
|
|
||||||
|
ユーザー名: {{ email }}
|
||||||
|
パスワード: {{ password }}
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
岐阜ロゲ in 大垣
|
||||||
|
運営:NPO 岐阜aiネットワーク
|
||||||
|
```
|
||||||
|
|
||||||
|
### 利用可能な変数
|
||||||
|
- `{{ team_name }}` - チーム名
|
||||||
|
- `{{ email }}` - メールアドレス
|
||||||
|
- `{{ password }}` - パスワード
|
||||||
|
- `{{ category }}` - 部門
|
||||||
|
- `{{ duration }}` - 時間
|
||||||
|
- `{{ leader_name }}` - 代表者名
|
||||||
|
- `{{ phone_number }}` - 電話番号
|
||||||
|
- `{{ member_names }}` - メンバー名
|
||||||
|
|
||||||
|
## 操作手順
|
||||||
|
|
||||||
|
### 1. 事前準備
|
||||||
|
1. CSVファイルを `CPLIST/input/team_mail.csv` に配置
|
||||||
|
2. メールテンプレートファイルを確認・編集
|
||||||
|
3. Docker環境が起動していることを確認
|
||||||
|
|
||||||
|
### 2. ドライラン(テスト実行)
|
||||||
|
実際にメールを送信する前に、テスト実行を行います:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/rogaining_srv
|
||||||
|
docker compose exec app python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv' --dry_run
|
||||||
|
```
|
||||||
|
|
||||||
|
**ドライランの確認項目:**
|
||||||
|
- CSVファイルが正常に読み込まれるか
|
||||||
|
- テンプレートが正しく適用されるか
|
||||||
|
- 送信対象の件数が正しいか
|
||||||
|
- メールの件名・本文のプレビューが正しいか
|
||||||
|
|
||||||
|
### 3. 実際のメール送信
|
||||||
|
ドライランで問題がないことを確認後、実際の送信を行います:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /path/to/rogaining_srv
|
||||||
|
docker compose exec app python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 送信結果の確認
|
||||||
|
コマンド実行後、以下の情報が表示されます:
|
||||||
|
- 処理行数
|
||||||
|
- メール送信数
|
||||||
|
- エラーがあった場合のエラー内容
|
||||||
|
|
||||||
|
## コマンドオプション
|
||||||
|
|
||||||
|
### 基本コマンド
|
||||||
|
```bash
|
||||||
|
python manage.py send_team_emails --csv_file='<CSVファイルパス>'
|
||||||
|
```
|
||||||
|
|
||||||
|
### オプション一覧
|
||||||
|
- `--csv_file`: CSVファイルのパス(必須)
|
||||||
|
- `--dry_run`: ドライラン(テスト実行)モード
|
||||||
|
- `--delay`: メール送信間隔(秒)デフォルト: 1秒
|
||||||
|
|
||||||
|
### 使用例
|
||||||
|
```bash
|
||||||
|
# ドライランモード
|
||||||
|
python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv' --dry_run
|
||||||
|
|
||||||
|
# 実際の送信
|
||||||
|
python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv'
|
||||||
|
|
||||||
|
# 送信間隔を3秒に設定
|
||||||
|
python manage.py send_team_emails --csv_file='CPLIST/input/team_mail.csv' --delay=3
|
||||||
|
```
|
||||||
|
|
||||||
|
## エラー対処法
|
||||||
|
|
||||||
|
### よくあるエラーと対処法
|
||||||
|
|
||||||
|
#### 1. CSVファイルが見つからない
|
||||||
|
```
|
||||||
|
CommandError: CSVファイルが見つかりません: CPLIST/input/team_mail.csv
|
||||||
|
```
|
||||||
|
**対処法:**
|
||||||
|
- ファイルパスを確認
|
||||||
|
- ファイル名のスペルミスをチェック
|
||||||
|
- ファイルが存在することを `ls -la CPLIST/input/` で確認
|
||||||
|
|
||||||
|
#### 2. テンプレートファイルが見つからない
|
||||||
|
```
|
||||||
|
TemplateDoesNotExist: emails/team_registration_subject.txt
|
||||||
|
```
|
||||||
|
**対処法:**
|
||||||
|
- テンプレートファイルが正しい場所に配置されているか確認
|
||||||
|
- ファイル名が正しいかチェック
|
||||||
|
- Docker容器を再起動: `docker compose restart app`
|
||||||
|
|
||||||
|
#### 3. SMTP接続エラー
|
||||||
|
```
|
||||||
|
SMTPException: SMTP Auth failure
|
||||||
|
```
|
||||||
|
**対処法:**
|
||||||
|
- メールサーバー設定を確認
|
||||||
|
- 認証情報(ユーザー名・パスワード)を確認
|
||||||
|
- ネットワーク接続を確認
|
||||||
|
|
||||||
|
#### 4. CSV読み込みエラー
|
||||||
|
**対処法:**
|
||||||
|
- CSVファイルの文字エンコーディング(UTF-8 BOM)を確認
|
||||||
|
- CSVヘッダーが正しいか確認
|
||||||
|
- 必須フィールドが欠けていないかチェック
|
||||||
|
|
||||||
|
## セキュリティ注意事項
|
||||||
|
|
||||||
|
1. **パスワード情報の取り扱い**
|
||||||
|
- CSVファイルには機密情報が含まれるため、適切なアクセス権限を設定
|
||||||
|
- 送信完了後はCSVファイルを安全な場所に移動またはバックアップ
|
||||||
|
|
||||||
|
2. **メール送信記録**
|
||||||
|
- 送信ログを保存し、送信状況を記録
|
||||||
|
- 重複送信を避けるため、送信済みチームを管理
|
||||||
|
|
||||||
|
3. **レート制限**
|
||||||
|
- 大量送信時はレート制限を考慮し、適切な間隔を設定
|
||||||
|
- SMTPサーバーの制限を確認
|
||||||
|
|
||||||
|
## トラブルシューティング
|
||||||
|
|
||||||
|
### Docker関連
|
||||||
|
```bash
|
||||||
|
# コンテナの状態確認
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# コンテナの再起動
|
||||||
|
docker compose restart app
|
||||||
|
|
||||||
|
# ログの確認
|
||||||
|
docker compose logs app
|
||||||
|
```
|
||||||
|
|
||||||
|
### データベース接続確認
|
||||||
|
```bash
|
||||||
|
# データベース接続テスト
|
||||||
|
docker compose exec app python manage.py dbshell
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSVファイル確認
|
||||||
|
```bash
|
||||||
|
# ファイル存在確認
|
||||||
|
ls -la CPLIST/input/
|
||||||
|
|
||||||
|
# ファイル内容確認
|
||||||
|
head -5 CPLIST/input/team_mail.csv
|
||||||
|
```
|
||||||
|
|
||||||
|
## 運用Tips
|
||||||
|
|
||||||
|
1. **バッチ送信**
|
||||||
|
- 大量のメール送信時は、CSVファイルを分割して複数回に分けて送信
|
||||||
|
- 送信間隔を適切に設定してサーバー負荷を軽減
|
||||||
|
|
||||||
|
2. **テスト環境での確認**
|
||||||
|
- 本番送信前に、テスト用メールアドレスでの動作確認を推奨
|
||||||
|
- ドライランを必ず実行
|
||||||
|
|
||||||
|
3. **バックアップ**
|
||||||
|
- 送信前にCSVファイルとテンプレートファイルをバックアップ
|
||||||
|
- 送信ログを保存
|
||||||
|
|
||||||
|
## 更新履歴
|
||||||
|
|
||||||
|
- 2025年9月5日: 初版作成
|
||||||
|
- 基本的なメール送信機能
|
||||||
|
- Django テンプレートシステム統合
|
||||||
|
- Outlook SMTP設定対応
|
||||||
|
|
||||||
|
## 連絡先
|
||||||
|
|
||||||
|
システムに関する問い合わせ:
|
||||||
|
- 運営:NPO 岐阜aiネットワーク
|
||||||
|
- メール:rogaining@gifuai.net
|
||||||
Reference in New Issue
Block a user