質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

7880閲覧

MailKitでメールを送信後、添付したファイルを削除しようとすると「別のプロセスで使用されているため~」のエラーが発生する。

ohno1011

総合スコア14

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2020/12/11 06:00

編集2020/12/11 07:11

MailKitでメールを送信し、その後ローカルにある添付ファイルを削除する処理があります。

MailKitでの送信時の処理

clsSendMail.cs

C#

1public bool SendMail() 2{ 3 4MimeKit.MimeMessage message = new MimeKit.MimeMessage(); 5 6//送付先の設定 7message.From.Add(new MimeKit.MailboxAddress("送信者名", "送信者アドレス")); 8message.To.Add(new MimeKit.MailboxAddress("宛先名", "宛先アドレス")); 9message.Subject = "件名"; 10 11string strText = "本文"; 12var textPart = new MimeKit.TextPart(MimeKit.Text.TextFormat.Plain); 13textPart.Text = strText; 14 15//添付ファイルを取得 16string FolderPath = "添付するファイルの保存ディレクトリ"; 17string FilePath = string.Empty; 18 19DirectoryInfo di = new DirectoryInfo(FolderPath); 20IEnumerable<DirectoryInfo> subFolders = di.EnumerateDirectories("*", SearchOption.AllDirectories); 21 22foreach (DirectoryInfo FolderName in subFolders) 23{ 24 if (cc.LeftByte(FolderName.Name, 3) == "宛先コード") 25 { 26 FilePath = FolderPath + FolderName + @"\"; 27 break; 28 } 29} 30 31string[] FileNames = Directory.GetFiles(FilePath, "*", SearchOption.TopDirectoryOnly); 32string[] Name = new string[9] { "", "", "", "", "", "", "", "", "" }; 33int intCnt = 0; 34foreach (string FileName in FileNames) 35{ 36 Name[intCnt] = cc.NullChecks(FileName); //宛先のフォルダ内にあるファイルを全て取得 37 intCnt++; //取得したファイルの数をカウント 38} 39 40//ファイルを添付(最大9個まで) 41var attachment1 = new MimeKit.MimePart(); 42var attachment2 = new MimeKit.MimePart(); 43var attachment3 = new MimeKit.MimePart(); 44var attachment4 = new MimeKit.MimePart(); 45var attachment5 = new MimeKit.MimePart(); 46var attachment6 = new MimeKit.MimePart(); 47var attachment7 = new MimeKit.MimePart(); 48var attachment8 = new MimeKit.MimePart(); 49var attachment9 = new MimeKit.MimePart(); 50 51MimeKit.MimePart[] attachments = new MimeKit.MimePart[9] 52 { attachment1,attachment2,attachment3,attachment4,attachment5, 53 attachment6,attachment7,attachment8,attachment9}; 54 55//ファイルの件数分、添付ファイルのpartを作成 56for (int i = 0; i < Name.Length; i++) 57{ 58 if (Name[i] != "") 59 { 60 attachments[i] = new MimeKit.MimePart() 61 { 62 Content = new MimeKit.MimeContent(File.OpenRead(Name[i])), 63 ContentDisposition = new MimeKit.ContentDisposition(), 64 ContentTransferEncoding = MimeKit.ContentEncoding.Base64, 65 FileName = Path.GetFileName(Name[i]) 66 }; 67 } 68} 69 70var multiPart = new MimeKit.Multipart("mixed"); 71multiPart.Add(textPart); 72for (int i = 0; i < intCnt; i++) 73{ 74 multiPart.Add(attachments[i]); 75} 76 77//MimeMessageを完成させる 78message.Body = multiPart; 79 80 //SMTPサーバーに接続してメールを送信する 81 using (var client = new MailKit.Net.Smtp.SmtpClient()) 82{ 83 try 84 { 85 client.Connect(SmtpServer, SmtpPort); 86 Console.WriteLine("接続完了"); 87 88 client.Authenticate(MailAddress, Password); 89 Console.WriteLine("認証完了"); 90 91 client.Send(message); 92 Console.WriteLine("送信完了"); 93 94 client.Disconnect(true); 95 Console.WriteLine("切断"); 96 } 97 catch (Exception ex) 98 { 99 errMessage = ex.ToString(); 100 } 101} 102 103if (errMessage != "") { return false; } 104return true; 105}

その後、ファイルを含むフォルダ削除の処理

Form1.cs

C#

1 private bool DirectoryDelete(string Path) 2 try 3 { 4 DirectoryInfo target = new DirectoryInfo(Path); 5 foreach (DirectoryInfo dir in target.GetDirectories()) 6 { 7 dir.Delete(true); ---8 } 9 return true; 10 } 11 catch(Exception ex) 12 { 13 errMessage = "ローカルの送信用フォルダ削除に失敗しました。"; 14 return false; 15 } 16 }

☆の処理で
System.IO.IOException: 別のプロセスで使用されているため、プロセスはファイル '〇〇〇.pdf' にアクセスできません。
というエラーが発生します。

メール送信先を複数選択することができ、その場合は全てにメール送信をした後にローカルのファイルをまとめて削除しています。
添付ファイル、添付ファイルの保存フォルダは宛先ごとにそれぞれ別で存在しています。
フォルダ1\001_A社\A社.pdf
フォルダ1\002_B社\B社.pdf
フォルダ1\003_C社\C社.pdf
といった感じです。

1か所しか送らないと、その送信先のファイルで削除時にエラーになります。

複数に送る場合、
001_A社
002_B社
003_C社
にコード順に送った場合、
最後に送信した003_C社のファイルだけ削除時にエラーになるようです。

となると添付ファイルのpartが追加してあるmessageの解放に問題があるのかと思うのですが、
Disposeメソッドが無くどうしたら良いのかわかりません。

何かわかる方がいらっしゃればご教示をお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/12/11 06:30 編集

> //message に対して各partの設定 ファイルのロックで不具合が出てるなら、ここを省略せずきちんと書いた方がいいと思いますけど。ファイル関係のStreamが開きっぱなしになってないですか?
退会済みユーザー

退会済みユーザー

2020/12/11 06:46 編集

ファイルを送信するには、そのファイルを開いて中身を読んでバイト列を取得する必要がありますが、「別のプロセスで使用されている」ということは、削除しようとしたときにはまだ開いたままになっているのでしょう。削除する前にきちんと閉じればよさそうですが、そこがどうなってるかコードも書いてないし、自分で考えて解決する他なさそうです。 質門の本題とは関係ないことですが、Exception を catch して例外を握りつぶしてしまうのは絶対に避けるべきです。他にやり方があるはず。
kikukiku

2020/12/11 06:58

下記の点が怪しいと思いました。 ・メールにファイルを添付するときに、ファイルを握ったままになっていないか? ・メール送信のインスタンスがきちんと終了しているか? ・上記で改善しない場合、数秒待ってから削除処理を開始してはどうか?
ohno1011

2020/12/11 07:07

radian様、SurferOnWww様、kikukiku様 回答ありがとうございます。 処理を省略せず記載するよう修正しました。
退会済みユーザー

退会済みユーザー

2020/12/11 07:12

以下は Microsoft のドキュメントの File.OpenRead メソッドのサンプルコードの一部です。このようにしてみたらどうなりますか? using (FileStream fs = File.OpenRead(path)) { // ・・・中略・・・ }
guest

回答1

0

ベストアンサー

C#

1 Content = new MimeKit.MimeContent(File.OpenRead(Name[i])),

ファイルがロックされたままになるということは、MimeContentクラスがFile.OpenReadで取得したFileStreamを処理した後、自動でClose(またはDispose)する仕様になっていないのかもしれません。
Streamがどのタイミングで読み取られるかは不明ですが、メール送信後は既に読み取っている筈なので、FileStreamを一旦Listなりに受け取り、メール送信後に自力でまとめてDisposeしてみてはどうでしょうか。

投稿2020/12/11 07:18

編集2020/12/11 07:49
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ohno1011

2020/12/11 08:09

解決しました。 var multiPart = new MimeKit.Multipart("mixed"); multiPart.Add(textPart); for (int i = 0; i < intCnt; i++) { multiPart.Add(attachments[i]); } ↓ List<MimeKit.MimePart> mimes = new List<MimeKit.MimePart>(); //☆ MimePartのListを作成 var multiPart = new MimeKit.Multipart("mixed"); multiPart.Add(textPart); for (int i = 0; i < intCnt; i++) { mimes.Add(attachments[i]); //☆ リストにMimePartを追加 multiPart.Add(attachments[i]); } 上記のようにListを作り //SMTPサーバーに接続してメールを送信する using (var client = new MailKit.Net.Smtp.SmtpClient()) {  //省略 } の後に foreach(var m in mimes) { m.Content.Stream.Dispose(); } という処理を書くことで削除のエラーが出なくなりました! radian様、SurferOnWww様、kikukiku様 回答頂き本当にありがとうございました。
退会済みユーザー

退会済みユーザー

2020/12/11 08:35 編集

MailKitでググってトップに出てきた@ITのサンプルが、添付ファイルのFileStreamのDisposeについては触れてないから、解放忘れてる人は結構居そうです。(いずれはデストラクタで解放されますが) https://www.atmarkit.co.jp/ait/articles/1811/21/news023.html
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問