반응형

Msgreader는 이메일 파일인 .msg와 .eml확장자 파일을 읽을 수 있도록하는 라이브러리입니다.
원본 github주소는 위 그림을 클릭하면 이동하실 수 있습니다.
이메일 파일에 담긴 이메일 정보(보낸이, 받는이, 보낸시각, 받은시각, cc, bcc, 메일제목, 메일내용, 첨부파일 등)의 정보를 읽을 수 있도록합니다.
상세한 예외처리는 제외하고 용법을 보겠습니다.
먼저, 메일정보를 쉽게 주고받을 수 있도록 프로퍼티를 충분히 가진 클래스를 선언하겠습니다.
class MailFile {
public string FileDirectory { get; set; } // 파일 경로
public string FileName { get; set; } // 파일명
public string FilePath { get; set; } // 파일경로 + 파일명
public string Originator { get; set; } // 보낸사람
public string Addressee { get; set; } // 받는사람
public string CC { get; set; } // CC
public string BCC { get; set; } // BCC
public DateTime SentDate { get; set; } // 발신 시간
public DateTime ReceivedDate { get; set; } // 수신 시간
public MailFile(string fileDirectory, string fileName)
{
FileDirectory = fileDirectory;
FileName = fileName;
FilePath = Path.Combine(fileDirectory, fileName);
// 그냥 string으로 더하지 않고 Path.Combine으로 쓴이유를 모른다면 독자는 꼭 찾아봐야한다!
}
}
예제이기 때문에 msg인지 eml파일인지 여부를 비교할 대상은 그냥 선언하겠습니다.
(여기서는 확장자로만 구분합니다.)
// 메일 파일을 읽기전에 있어야할 것들을 기입한 부분입니다.
// msg인지 eml인지 비교할 확장자,
// MailFile 클래스의 선언
// 생성된 첨부파일을 다운받을 경로 등
string msgExtention = ".MSG";
string emlExtention = ".EML";
string mailFileDirectory = @"파일경로, \가 보통들어가서 @를 붙임";
string mailFileName = @"파일명";
var mailFile = new MailFile(mailFileDirectory, mailFileName);
string downloadDirectory = @"첨부파일이있다면 다운받을 경로이다.";
다음은 메일파일의 정보가 있는지 여부를 받아서 받아오는 것이다.
FileInfo mailFileInfo = new FileInfo(mailFile.FilePath);
if (fileInfo.Exists && fileInfo.Length > 0)
// fileInfo.Exists는 파일이 존재하는지 여부를 리턴
// fileInfo.Length는 파일의 크기를 byte단위로 리턴
{
if (mailFileInfo.Extension.ToUpper().Equals(msgExtention))
// 파일 경로 비교 ToUpper()를 해도되고 StringComparison.OrdinalIgnoreCase 를 사용해도된다.
{
using var msgFile = new MsgReader.Outlook.Storage.Message(mailFilePath);
// 메일 파일의 경로에 따라 여기서는 확장자값이 .MSG이면 msg인스턴스(Storage.Message)를 생성한다.
// 아래는 읽으면 감이 올 것이다. 각 정보를 받아오는 것이고
// 여기에 매칭되도록 초반에 MailFile을 선언했다.
// 실제 사용시에는 MailFile에 첨부파일 존재여부도 넣어주면 좋다.
mailFile.Originator = msg.Sender?.DisplayName; // 보낸이
mailFile.Addressee = msg.GetEmailRecipients(RecipientType.To, false, false); // 받는이
mailFile.CC = msg.GetEmailRecipients(RecipientType.Cc, false, false); // CC
mailFile.BCC = msg.GetEmailRecipients(RecipientType.Bcc, false, false); // BCC
mailFile.SentDate = msg.SentOn ?? DateTime.MinValue; // 보낸시각
mailFile.ReceivedDate = msg.ReceivedOn ?? DateTime.MinValue; // 받는시각
// 첨부파일은 아래와 같은방법으로 가져올 수 있다.
// #### 첨부파일류들은 data[]로 파일데이터를 들고있기때문에 아주 무겁다. ####
// ## 그러나 IDisposable을 구현하고 있어서 dispose()나 using을 사용할 수 있다.
// ## 해당부분은 여기에서는 포함하고 있지 않아서 참고하여 개발시 이 부분을 반드시 확인하기바란다.
// ## 아니면 메모리가 탈탈 털리는 현상을 볼 지도...
// ## 또한 파일데이터를 들고있기때문에 너무 용량이 큰 친구들은 이것으로 첨부파일 뽑으려면
// ## 메모리가 아주커야할 것이다... 파일 용량에 꼭 제한을 두자.
// ## 도입부에 FileInfo 선언했는데 거기서 처리할 수 있다.
var attachmentsObject = msgFile.Attachments;
attachmentsObject.ForEach(attachment =>
{
try
{
if (!Directory.Exists(downloadDirectory)){ // 첨부파일을 다운받을 경로가 없으면 만든다.
Directory.CreateDirectory(downloadDirectory);
}
if (attachment != null && attachment is Storage.Attachment) // 일반적인 첨부파일이면
{
var attachmentCast = attachment as Storage.Attachment ?? throw new Exception($"형변환했는데 null이면 던질 예외");
string attachmentPath = Path.Combine(downloadDirectory, attachmentCast.FileName); // 내려받을 첨부파일 path
File.WriteAllBytes(attachmentPath, attachmentCast.Data); // 다운로드
}
else if (attachment != null && attachment is Storage.Message) // 앞에 using var msgFile = new MsgReader.Outlook.Storage.Message(mailFilePath); 부분을 보면 눈치 챘을 수도 있지만 이는 첨부파일이 MSG파일인 경우이다.
{
var attachmentCast = attachment as Storage.Message ?? throw new Exception($"형변환했는데 null이면 던질 예외");
string attachmentPath = Path.Combine(downloadDirectory, attachmentCast.FileName);
attachmentCast.Save(attachmentPath); // Storage.Message는 Save함수를 사용하여 파일을 내려받아야 한다.
}
else
{
// 둘다 아닌경우에 취할 조치를 하면 된다. 예외처리를 해도 좋다.
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
});
}
else if (mailFileInfo.Extension.ToUpper().Equals(emlExtention))
{
var emlFile = MsgReader.Mime.Message.Load(mailFileInfo); // eml 파일을 읽는 방법이다.
if (emlFile.Headers != null) // eml 파일의 메일 파일정보 불러오기는 복잡하다... msgReader 공식 문서를 참조하면 이렇게 해야한다.
{
if (emlFile.Headers.From != null && !string.IsNullOrEmpty(eml.Headers.From.DisplayName))
{ mailFile.Originator = emlFile.Headers.From.DisplayName.ToString().Replace("\"", string.Empty); }
else if (eml.Headers.From != null && !string.IsNullOrEmpty(eml.Headers.From.Address))
{ mailFile.Originator = emlFile.Headers.From.Address.ToString().Replace("\"", string.Empty); }
else { mailFile.Originator = ""; }
emlFile.Headers.To.ForEach(to => mailInfo.Addressee += "," + to.ToString());
if (mailFile.Addressee == null) { mailFile.Addressee = ""; }
else { mailFile.Addressee = mailFile.Addressee.Substring(1).Replace("\"", string.Empty); }
emlFile.Headers.Cc.ForEach(cc => mailFile.CC += "," + cc.ToString());
if (mailFile.CC == null) { mailFile.CC = ""; }
else { mailFile.CC = mailFile.CC.Substring(1).Replace("\"", string.Empty); }
emlFile.Headers.Bcc.ForEach(bcc => mailFile.BCC += "," + bcc.ToString());
if (mailFile.BCC == null) { mailFile.BCC = ""; }
else { mailFile.BCC = mailInfo.BCC.Substring(1).Replace("\"", string.Empty); }
if (emlFile.Headers.DateSent != null) { mailFile.SentDate = emlFile.Headers.DateSent; }
else { mailFile.SentDate = DateTime.MinValue; }
if (emlFile.Headers.Received != null && emlFile.Headers.Received.Count > 0)
{
mailFile.ReceivedDate = emlFile.Headers.Received.Last().Date;
}
else
{
mailFile.ReceivedDate = DateTime.MinValue;
}
} // 여기까지가 메일정보 읽기
ObservableCollection<MessagePart> attachments = emlFile.Attachments;
var attachmentsCount = attachments.Count;
foreach (var attachment in attachments) // eml파일은 정보읽기는 복잡하지만 첨부파일 다운로드는 간단하다.
{
try
{
if (!Directory.Exists(downloadDirectory))
Directory.CreateDirectory(downloadDirectory);
if (attachment.IsAttachment)
attachment.Save(new FileInfo(Path.Combine(downloadDirectory, attachment.FileName)));
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
}
}
생각보다 코드가 길기 때문에 설명도 코드블럭내에 같이 적어놨습니다. 특히 ####, ## 붙은 부분을 반드시 읽어서 참고시에 메모리 등 관리문제를 최대한 방지 하시기 바랍니다.
반응형
'주요 언어 - 플랫폼 > C# - .NET' 카테고리의 다른 글
| [C#] 초성을 포함한 StartWith 함수 만들기 (1) | 2024.05.08 |
|---|---|
| [c# / .NET] 설정 파일을 읽는 법에 대하여(.json/.ini) (0) | 2024.03.19 |
| [.NET 라이브러리] System.Text.Json (0) | 2023.11.07 |
| [c# dotnet nuget] Newtonsoft.Json (0) | 2023.10.27 |
| [c# - dotnet nuget] serilog (0) | 2023.10.26 |