【MailKit】オープンソースを利用してVBAでメールを送信する

# 1. VBAでメールを送信する主な方法

VBAでメール機能を実装する方法はいくつかあります。
SMTPサーバ経由でメールを送信するには、Windows標準の[CDO](https://support.microsoft.com/ja-jp/help/2028411/collaboration-data-objects-cdo-1-2-1-is-not-supported-with-outlook-201)を使う方法や、.NET Frameworkの[SmtpClientクラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.net.mail.smtpclient?view=net-5.0)を使用する方法などがあります。
しかし、CDOは20年以上前の技術のため使用できないドメインがあったり、SmtpClientは廃止が決定しているなど、実際に使用するには難があります（下表のとおり）。

|ライブラリ名|送信方法|参考サイト|備考|
|---|---|---|---|
|[CDO](https://support.microsoft.com/ja-jp/help/2028411/collaboration-data-objects-cdo-1-2-1-is-not-supported-with-outlook-201)<br>（Collaboration Data Objects）|SMTPサーバにアクセス|[VBAでメール送信する（エクセルの神髄）](https://excel-ubara.com/excelvba4/EXCEL233.html)<br>[CDO.Messageによるメール送信](http://serialty.blog117.fc2.com/blog-entry-10.html)|Windows標準だが、技術が古くSTARTTLSに非対応（[参考記事](http://hiroses.seesaa.net/article/365310670.html)）|
|[SmtpClientクラス](https://docs.microsoft.com/ja-jp/dotnet/api/system.net.mail.smtpclient?view=net-5.0)<br>（.NET Framework）|SMTPサーバにアクセス|[外部ライブラリを作成してVBAでメールを送信する方法(SmtpClient使用)](https://www.lifedesignedit.com/sending_email_using_vba_by_dotnet_library)|SmtpClientは廃止された（[参考記事](https://elleneast.com/?p=10085)）|
|[Outlookオブジェクト](https://docs.microsoft.com/ja-jp/office/vba/api/overview/outlook/object-model)|Outlookを自動操作|[Outlookオブジェクトを用いたメール送信の基本事項](https://qiita.com/t-yama-3/items/c23b700162aa3ede9eb7)|現環境で安定的に動作するが、メーラーの自動操作のため汎用性は低い|
|[MailKit](https://github.com/jstedfast/MailKit)ライブラリ|SMTPサーバにアクセス|[電子メールを送信するには？（MailKit編）［.NET 4.5、C#／VB］](https://www.atmarkit.co.jp/ait/articles/1811/21/news023.html)|VBAに関する文献が見当たらない|

以上の状況を踏まえて、**[MailKit](https://github.com/jstedfast/MailKit)**というオープンソースライブラリを利用してメール送信する方法を確認・検討することにしました。
Microsoft側も[MailKitの使用を推奨している](https://docs.microsoft.com/ja-jp/dotnet/api/system.net.mail.smtpclient?view=net-5.0#remarks)ので、.NET Frameworkではこのライブラリを使うことがスタンダードになるものと思われます。

VBAにMailKitを導入するために、外部ライブラリ（[DLL：ダイナミックリンクライブラリ](https://docs.microsoft.com/ja-jp/troubleshoot/windows-client/deployment/dynamic-link-library)）を作成することとします。
なお、普段使っている技術ではなく、あくまで実験的な取組みのため、誤りなどありましたら、ご意見やご指摘などいただければ幸いです。

念のためですが、作成したいツールが**Outlookオブジェクト**の使用で済むならばそれが一番です。
他者に提供するVBAマクロに**MailKit**を使用する場合は、自身で色々と調べてから、適切なリスク回避をとるようにしてください。

＜**目次**＞
[1. VBAでメールを送信する主な方法](#1-vbaでメールを送信する主な方法)
[2. MailKitを使用する外部ライブラリ（DLL）の作成](#2-mailkitを使用する外部ライブラリdllの作成)
[3. MailKitを使用するDLLのソースコード記述](#3-mailkitを使用するdllのソースコード記述)
[4. VBAでの実行](#4-vbaでの実行)
[5. 作成したDLLの配布（他のPCでの実行）](#5-作成したdllの配布他のpcでの実行)

# 2. MailKitを使用する外部ライブラリ（DLL）の作成

DLLの作成にはVisual Studioを使用します。インストール方法は様々なサイトで[解説](https://www.fenet.jp/dotnet/column/windows/1312/)されていますので、調べてみてください。
ここでは、Visual Studio Community 2019を使用します（商用に利用する場合は一定の制限がありますのでご注意ください）。

＜**DLL作成についての参考サイト**＞
・[VBAから扱えるDLLの作成](https://excel.syogyoumujou.com/memorandum/dll_1.html)
・[VisualBasicでのCOMオブジェクトの作成](https://docs.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/com-interop/walkthrough-creating-com-objects)
・[VBAから扱えるDLLをC#で書いてみる。](https://www.ka-net.org/blog/?p=5464)
・[VBAで独自の.NETライブラリを使うには？](https://www.atmarkit.co.jp/fdotnet/dotnettips/1063vbausedotnet/vbausedotnet.html)

## 2-1. 新規プロジェクトの作成

DLL作成の作業においてはWindowsのレジストリの変更も行いますので、Visual Studio起動の際には、次のように右クリックから「その他」を開いて「管理者として実行」をする必要があります。
![2021-02-01 225302.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/26845bf0-792c-8c92-6e9f-3d93e4fd6c3b.png)

起動すると次のような画面になりますので、「新しいプロジェクトの作成」をクリックします。
![2021-01-25 211148.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/4470d9cc-7a43-1b39-606b-5ff43e06a3e3.png)

次に「クラスライブラリ (.NET Framework)」を選択して「次へ」のボタンをクリックします。
![2021-01-25 211452.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/7c136228-c8be-c5a3-e7ad-76feb60945a5.png)

表示された画面で、プロジェクト名を指定します。
何でも良いのですが、ここでは「MailKitLibrary」というプロジェクト名にしておきます。
![2021-01-25 211744.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/500aeb2a-e990-ff43-84c6-e8708046fa31.png)

プロジェクトが無事に作成されると次のような画面が表示されます。
![2021-01-25 212649.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/2ecd1160-80ff-32d1-e601-a3d6cda460b0.png)

## 2-2. MailKitのインストール

オープンソースのMailKitは標準のOSには入っていないため、別途インストールする必要があります。
メニュー「ツール」から「NuGetパッケージマネージャー」を選択して、「ソリューションのNuGetパッケージの管理」をクリックします。
![2021-01-25 212911.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/3f90dbd3-b2b6-7c49-1b53-70cb12ceac55.png)

「参照」タブからMailKitを検索して、表示されたMailKitパッケージをクリックします。
![2021-01-25 213048.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/632375b6-5ccb-2f1d-3c11-c2f148ee31fd.png)

右側に表示された「MailKitLibrary」にチェックを入れて、インストールボタンをクリックします。
（元のライブラリ名とプロジェクト名が被ってしまってますね。少々反省です）
私の環境では、インストールに10秒ほどかかりました。
![2021-01-25 213305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/e83ce907-b743-9280-28b8-3167f47a04b9.png)

## 2-3. 64ビット版のDLLを作成する場合

＜**参考記事**＞
[Visual Studio 2013で64ビットバイナリを作成する](https://qiita.com/imura/items/076196b50f105c3138f7)

DLLは、使用する環境に合わせて、**32ビット版**か**64ビット版**のいずれかで作成します（使用するExcelやAccessの環境を確認してみてください。Office2019以降では、標準で64ビット版になっています）。
なお、32ビット版で作成したDLLでも、64ビットの方のレジストリに登録すれば（後述）、64ビット版のExcelにおいても普通に動作しました（この辺は正直よくわかりません）。
何にしろ、現在のExcelは64ビット版が標準になっていますので、64ビット版で作成する方法も把握しておいた方が良いでしょう。

Visual Studioでは、デフォルトで32ビット版のDLLが作成されますので、64ビット版で作成する場合は、以下のように設定する必要があります。
まず、「ソリューションエクスプローラー」のソリューション名（ツリーの一番上のところ）のところを右クリックします。
![2021-01-25 213710.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/66e9e49f-4541-b779-9560-917a9c92f8c4.png)

表示されたメニューから「プロパティ」を選択します。
![2021-01-25 214008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/72e7e60b-da4f-e1aa-72fb-d3fcae45bdad.png)

プロパティページが開きますので、左側の「構成プロパティ」の「構成」をクリックします。
そうすると、右上の「構成マネージャー」ボタンが押せるようになりますのでクリックして開きます。
![2021-01-25 214158.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/a9b4be6e-4c81-6ec9-3502-cb80348cd01d.png)

構成マネージャー画面の右上「アクティブソリューションプラットホーム」のタブから「＜新規作成＞」を選びます。
![2021-01-25 214327.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/daf6b618-9655-3d93-d866-46c115ade272.png)

新しいソリューションプラットフォーム画面の「新しいプラットフォームを入力または選択してください」タブから「x64」を選んで、新しいプラットフォームを作成するにチェックを入れてOKボタンをクリックします（次のとおり）。
![2021-01-25 214510.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/ad743682-ca78-ceb1-b635-5a130a53d58b.png)

構成マネージャー画面で「x64」が選択された状態になっていると思います。
これで「閉じる」ボタンを押して終了です。
![2021-01-25 214610.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/97436cde-607b-86ad-66fc-eb0796b56fba.png)

## 2-4. COM相互運用機能の登録

**COM（Component Object Model）**とは、「マイクロソフトが提唱するソフトウェアの再利用を目的とした技術」（[Wikipedia](https://ja.wikipedia.org/wiki/Component_Object_Model)より）です。
作成したDLLはそのままではVBAでは使用できないので、このCOMを使用してVBAからDLLを参照できるようにする必要があります。
設定方法は簡単で、Visual Studioで次の手順で行えば大丈夫です。

ソリューションエクスプローラーのプロジェクト名（ツリーの2番目のところ）のところを右クリックします。
![2021-01-25 220737.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/29c7be88-9718-5c09-9819-1b281f99eef2.png)

現れたメニューから「プロパティ」を選択します。
![2021-01-25 221822.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/a0761a73-12b6-66e4-7f1d-9d4608e1479c.png)

プロパティ画面の左側の項目のうち「コンパイル」を選択して、下の方にある「COM相互運用機能の登録」にチェックを入れます。
![2021-01-25 222019.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/b09bfdff-9f08-1656-a01d-f0584ff9617e.png)

次に、左側の項目の「アプリケーション」を選択して「アセンブリ情報」ボタンをクリックします。
![2021-01-31 152324.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/ceee623e-2b17-b37a-7df6-60aa2fdd68e0.png)

アセンブリ情報の画面で、「アセンブリをCOM参照可能にする」のところにチェックを入れます（入っていたらそのままでOKです）。
![2021-01-31 152448.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/df6b12a7-5834-5e8f-9ed9-10772df1e19e.png)
OKボタンを押して設定は完了です。
これで、コンパイル時にWindowsの[レジストリ](https://ja.wikipedia.org/wiki/%E3%83%AC%E3%82%B8%E3%82%B9%E3%83%88%E3%83%AA)に登録されることになり、VBAから参照できるようになります。

なお、青枠部分の[GUID（Globally Unique Identifier）](https://ja.wikipedia.org/wiki/GUID)は、作成したクラスライブラリを参照するための識別子となります。


＜**参考サイト**＞
[COMの基礎](http://chokuto.ifdef.jp/urawaza/com/com.html)
[C#のCOM相互運用機能の登録チェックボックスの機能について](https://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=31944&forum=7)

# 3. MailKitを使用するDLLのソースコード記述

以下、**VB.NET**でコードを記述していきます。
VB.NETは、私も普段は使わないですが、基本はVBAと同じなのでそんなに難しいことはないと思います。

ごちゃごちゃしたコードは分かりにくいので、最初は基本的な機能を実装するサンプルを書いた上で、その後に、実際にDLLとして記載するコードを貼っておきます。

＜**MailKitについての参考サイト**＞
・[電子メールを送信するには？（MailKit編）［.NET 4.5、C#／VB］](https://www.atmarkit.co.jp/ait/articles/1811/21/news023.html)
・[[PowerShell]MailKitを使ってメールを送信する方法](https://www.ka-net.org/blog/?p=11087)
・[MailKitドキュメント](http://www.mimekit.net/docs/html/Introduction.htm)

## 3-1. コードの記述の基本形（VB.NET）

まず、参考として、MailKitでメール送信を実装する場合の[基本形のコード](http://www.mimekit.net/docs/html/Creating-Messages.htm)を見ていきます。
最小の項目で書くと次のような感じになります。

### 3-1-1. シンプルなソースコード

<font color="red">※以下はMailKitライブラリの基本事項を確認するためのもので、実際にDLLに記載するコードではありません</font>

```vb
Imports System.IO

Module Module1
    Public Sub SendMailSimple()
        'MimeMessageクラスのインスタンスを作成
        Dim message = New MimeKit.MimeMessage()

        'アドレスの設定
        message.From.Add(New MimeKit.MailboxAddress("t-yama", "XXXXXXXXX@XXX.ne.jp")) '送信者（第一引数は表示名、第二引数はメールアドレス）
        message.To.Add(New MimeKit.MailboxAddress("yamada", "YYYYYYYYYY@YYY.ne.jp")) '宛先（同上）
        message.Subject = "こんにちは" '件名

        '本文の作成
        Dim textPart = New MimeKit.TextPart("Plain") 'TextPartクラスのインスタンス作成（本文はテキスト形式と指定）
        textPart.Text = "VBでMimeKitを使用してメールを送信します" 'TextPartクラスに本文を格納
        message.Body = textPart 'messageオブジェクトにTextPartクラス（本文）を格納

        'SMTPサーバに接続してメール送信を実行
        Dim client = New MailKit.Net.Smtp.SmtpClient() 'SMTPクライアントクラスのインスタンスを作成
        client.ServerCertificateValidationCallback = Function(s, c, h, e) True 'SMTPサーバが暗号化に対応していない場合に記述（SSL証明書のエラーを回避）
        client.Connect("ybbsmtp.mail.yahoo.co.jp", 465, MailKit.Security.SecureSocketOptions.Auto) 'SMTPサーバのURLとポート番号を指定
        client.Authenticate("XXXXXXXXXX", "PPPPPPPP") '第一引数はアカウント名、第二引数はパスワード
        client.Send(message) 'メールを送信
        client.Disconnect(True) '接続を解除
    End Sub
End Module
```

### 3-1-2. 簡単な説明

#### 3-1-2-1. MimeMessageクラス

まず、[MimeMessageクラス](http://www.mimekit.net/docs/html/T_MimeKit_MimeMessage.htm)のインスタンス（オブジェクト）を作成します。

```vb
Dim message = New MimeKit.MimeMessage()
```

作成されたmessageオブジェクトに、送信者（Fromプロパティ）、宛先（To, Cc, Bccプロパティ）、件名（Subjectプロパティ）、本文（Bodyプロパティ）などの情報をセットします（上のコード中、「アドレスの設定」および「本文の作成」のところです）。

メール本文をセットする[TextPartクラス](http://www.mimekit.net/docs/html/T_MimeKit_TextPart.htm)のインスタンス作成のところは、プレーンテキスト （plain text）で指定していますが、HTML形式で送信する場合は、次のように書きます（詳しくは[こちら](http://www.mimekit.net/docs/html/T_MimeKit_Text_TextFormat.htm)を参照）。

```vb
Dim textPart = New MimeKit.TextPart("Html")
textPart.Text = "VBで<b>MimeKit</b>を使用してメールを送信します"
message.Body = textPart
```

#### 3-1-2-2. SmtpClientクラス

電子メールメッセージの送信に使用できる[SmtpClientクラス](http://www.mimekit.net/docs/html/T_MailKit_Net_Smtp_SmtpClient.htm)のインスタンス（オブジェクト）を作成します。

```vb
Dim client = New MailKit.Net.Smtp.SmtpClient() 'SMTPクライアントクラスのインスタンスを作成
```

作成されたclientオブジェクトに、SMTPサーバのURL、ポート番号、使用するアカウント名、パスワードなどをセットして、SMTPサーバと通信を行います。

なお、SMTPサーバが暗号化に対応していない場合には、次の1行が必要となります（[前述の記事](https://www.atmarkit.co.jp/ait/articles/1811/21/news023.html)の丸ごと受け売りです）。

```vb
client.ServerCertificateValidationCallback = Function(s, c, h, e) True
```

これは、SSLで使用されるデジタル証明書が、信頼されないものと認識された場合に生じるエラーを回避するためのもののようです（「[SSL通信で信頼されない証明書を回避するには？](https://www.atmarkit.co.jp/fdotnet/dotnettips/867sslavoidverify/sslavoidverify.html)」を参照）。
使用するSMTPサーバによって記述の要否が異なるものと思われますが、現時点ではこの1行を入れておいても動作に影響がないため、どの場合にもデフォルトで入れるようにしています（誤りであればご指摘をいただけると幸いです）。

## 3-2. DLL用に記載するソースコード

実際に、DLL用に記載するソースコードは、プロジェクト作成時に生成されている「Class1.vb」ファイルに記述します。
ファイル名は変えても差し支えありません。

もっと適切な書き方もあると思いますが、私の場合は、次のように記載しています。

### 3-2-1. 実際にDLL作成用として記載するソースコード

```vb
Imports System.IO

Namespace MailKitClass
    Public Class MailKitClass
        Async Sub SendByMailKitAsync(fromAddress() As String, toAddress(,) As String, ccAddress(,) As String, bccAddress(,) As String,
                             server As String, port As Long, account As String, password As String,
                             subject As String, bodyText As String, Optional mimeType As String = "", Optional filePath As String = "")
            'アドレスの設定
            Dim message = New MimeKit.MimeMessage()
            message.From.Add(New MimeKit.MailboxAddress(fromAddress(1), fromAddress(0)))
            Dim i As Long
            For i = 0 To UBound(toAddress, 2)
                message.To.Add(New MimeKit.MailboxAddress(toAddress(1, i), toAddress(0, i)))
            Next i
            If ccAddress(0, 0) <> "" Then
                For i = 0 To UBound(ccAddress, 2)
                    message.Cc.Add(New MimeKit.MailboxAddress(ccAddress(1, i), ccAddress(0, i)))
                Next i
            End If
            If bccAddress(0, 0) <> "" Then
                For i = 0 To UBound(bccAddress, 2)
                    message.Bcc.Add(New MimeKit.MailboxAddress(bccAddress(1, i), bccAddress(0, i)))
                Next i
            End If
            message.Subject = subject

            '本文の作成
            Dim body = New MimeKit.TextPart(MimeKit.Text.TextFormat.Html)
            body.Text = bodyText

            If filePath <> "" Then
                'メッセージ内容の作成（本文と添付ファイルを設定）
                Dim multipart = New MimeKit.Multipart("mixed")
                multipart.Add(body)

                'ファイルの添付
                Dim attachment = New MimeKit.MimePart(mimeType)
                attachment.Content = New MimeKit.MimeContent(File.OpenRead(filePath))
                attachment.ContentDisposition = New MimeKit.ContentDisposition()
                attachment.ContentTransferEncoding = MimeKit.ContentEncoding.Base64
                attachment.FileName = Path.GetFileName(filePath)
                multipart.Add(attachment)

                message.Body = multipart
            Else
                'メッセージ内容の作成（本文のみ設定）
                message.Body = body
            End If

            'SMTPサーバに接続してメール送信を実行
            Dim client = New MailKit.Net.Smtp.SmtpClient()
            client.ServerCertificateValidationCallback = Function(s, c, h, e) True
            Await client.ConnectAsync(server, port)
            Await client.AuthenticateAsync(account, password)
            Await client.SendAsync(message)
            Await client.DisconnectAsync(True)
        End Sub
    End Class
End Namespace
```

DLL作成のために記載すべきコードは、以上です。

### 3-2-2. 簡単な説明

基本的なところは「[3-1. コードの記述の基本形（VB.NET）](#3-1-コードの記述の基本形vbnet)」と変わりません。

メールごとに変わる情報（送信者、宛先、本文、SMTPサーバ、アカウント名など）は、全て変数にして、VBA側で指定できるようにしています。

なお、宛先は複数の場合もあるので、配列で渡せるようにしています（配列を使用すると汎用性がなくなるので良くないかもしれません）。
配列には、「アドレス」「表示名」の順序で入れるようにしていますが、この順序も好みがあると思います（表示名が不要な場合は空文字「""」を渡します）。

### 3-2-3. 非同期処理（AsyncおよびAwait）

また、SMTPサーバと通信するには時間が掛かってしまうので、応答を待たずに次の処理に進められるように[AsyncおよびAwaitを使用した非同期処理](https://docs.microsoft.com/ja-jp/dotnet/visual-basic/programming-guide/concepts/async/)を使用しています（参考にさせていただいたサイトの例にならっています）。
これを使うのと使わないのでは、処理効率が全然変わってきます。
SmtpClientクラスのメソッドも、それぞれ非同期用のメソッドを使用しています。
まとめると次のとおりです。

|同期処理|非同期処理|備考|
|---|---|---|
|[Connectメソッド](http://www.mimekit.net/docs/html/Overload_MailKit_Net_Smtp_SmtpClient_Connect.htm)|[ConnectAsyncメソッド](http://www.mimekit.net/docs/html/Overload_MailKit_Net_Smtp_SmtpClient_ConnectAsync.htm)|SMTPサーバーへの接続を行う|
|[Authenticateメソッド](http://www.mimekit.net/docs/html/Overload_MailKit_Net_Smtp_SmtpClient_Authenticate.htm)|[AuthenticateAsyncメソッド](http://www.mimekit.net/docs/html/Overload_MailKit_Net_Smtp_SmtpClient_AuthenticateAsync.htm)|アカウント、パスワードなどで認証する|
|[Sendメソッド](http://www.mimekit.net/docs/html/Overload_MailKit_Net_Smtp_SmtpClient_Send.htm)|[SendAsyncメソッド](http://www.mimekit.net/docs/html/Overload_MailKit_Net_Smtp_SmtpClient_SendAsync.htm)|メッセージを送信する|
|[Disconnectメソッド](http://www.mimekit.net/docs/html/M_MailKit_Net_Smtp_SmtpClient_Disconnect.htm)|[DisconnectAsyncメソッド](http://www.mimekit.net/docs/html/M_MailKit_Net_Smtp_SmtpClient_DisconnectAsync.htm)|接続を切断する|

例外処理（try～catch）はうまくハマらなかったので入れていません。エラーはVBA側で拾うことにしました。
気になる方は、「[async／awaitで例外処理をするには？［C#／VB］](https://www.atmarkit.co.jp/ait/articles/1805/16/news018.html)」などを参考にしてみてください。

### 3-2-4. ファイルを添付する

ファイルを添付するには、[Multipartクラス](http://www.mimekit.net/docs/html/T_MimeKit_Multipart.htm)のインスタンスを作成して、最初にメッセージ本文、次に添付するファイルを追加します。
基本は、前述の記事の「[ファイルを添付するには？](https://www.atmarkit.co.jp/ait/articles/1811/21/news023.html#attachment)」の部分を参考にさせていただいています。

**ファイルを添付する部分のソースコード抜粋**

```vb
'Multipartクラスのインスタンスを作成
Dim multipart = New MimeKit.Multipart("mixed")

'本文の作成
Dim body = New MimeKit.TextPart("Html")
body.Text = bodyText
multipart.Add(body)

'ファイルの添付
Dim attachment = New MimeKit.MimePart("text/plain") 'MimePartクラスのインスタンスを作成（MimeTypeを指定）
attachment.Content = New MimeKit.MimeContent(File.OpenRead("C:\Users\username\Documents\Test.txt")) '添付するファイルのフルパスを記載
attachment.ContentDisposition = New MimeKit.ContentDisposition() 'これは何故必要なのか不明（なくともメール送信可能）
attachment.ContentTransferEncoding = MimeKit.ContentEncoding.Base64 'エンコード方式の指定
attachment.FileName = "Test.txt" '添付するファイル名（ファイル名の変更もできる）
multipart.Add(attachment)

message.Body = multipart 'Multipartクラスのインスタンスをmessageオブジェクトにセットする
```

#### 3-2-4-1. MimeTypeの指定

`New MimeKit.MimePart("text/plain")`のところでMimePartクラスのインスタンスを作成するとともに、[MimeType](https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)を「text/plain」と指定しています。
MimeTypeはファイルの種類（性質）を指定するもので、[こちらのリンク](https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)に主なMimeTypeが列挙されているので参考にしてください。
ファイルの種類が指定できなければ「[application/octet-stream](https://wa3.i-3-i.info/word15821.html)」というMimeTypeを指定すれば、結構万能に処理してくれるようですが、これでテキストファイルを送ると迷惑メールと判定されたので、拡張子からMimeTypeを導き出す関数などを作った方が良さそうです。

#### 3-2-4-2. 添付ファイルの指定

MimePartクラスの[Contentプロパティ](http://www.mimekit.net/docs/html/P_MimeKit_MimePart_Content.htm)で、送信するファイルを指定します（フルパスです）。
MimePartクラスの[FileNameプロパティ](http://www.mimekit.net/docs/html/P_MimeKit_MimePart_FileName.htm)では、送信するファイルの名前を指定します。あくまで名前の指定なので、オリジナルと異なるファイル名を付けることもできます。

#### 3-2-4-3.エンコード方式の指定

MimePartクラスの[ContentTransferEncodingプロパティ](http://www.mimekit.net/docs/html/P_MimeKit_MimePart_ContentTransferEncoding.htm)では、ファイル送信のエンコード方式を指定します。
ここで指定している[Base64](https://ja.wikipedia.org/wiki/Base64)は、「データを64種類の印字可能な英数字のみを用いて、それ以外の文字を扱うことの出来ない通信環境にてマルチバイト文字やバイナリデータを扱うためのエンコード方式」であり、「7ビットのデータしか扱うことの出来ない電子メールにて広く利用されている」とのことです。

#### 3-2-4-4. ContentDispositionプロパティ

なお、[ContentDispositionプロパティ](http://www.mimekit.net/docs/html/P_MimeKit_MimeEntity_ContentDisposition.htm)の役割はいまいち分かりません。
参考にさせていただいたサイトには全てこのプロパティ記載されていましたので、そのまま書いています。
しかし、インスタンスを生成しただけで、他に何もしてないように見えますがどうなんでしょう（無知がゆえ、さっぱりわかりません）。
ちなみに、この1行がなくてもファイルの添付は可能でした。でも、分からないので当然残しておきます。


＜**参考サイト**＞
[ファイルを添付するには？](https://www.atmarkit.co.jp/ait/articles/1811/21/news023.html#attachment)
[添付ファイル付きのメッセージを作成するにはどうすればよいですか？](http://www.mimekit.net/docs/html/Frequently-Asked-Questions.htm#CreateAttachments)

## 3-3. コンパイルの実行

コードの記載が終わったら、コンパイルの実行をします。
次の図のように、構成は「Debug」のままで「開始」ボタンをクリックします。
![2021-01-25 222305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/ecd786b5-1807-a1ab-64f5-0e5d281c715f.png)
なお、最初から構成を「Release」にしてもさして違いはないと思いますが、固定観念として開発中は「Debug」、配布するときは「Release」としておけばよいと思います（参考として「[Debug構成とRelease構成の違い](https://tekk.hatenadiary.org/entry/20120524/1337873495)」）。

実行ボタンを押してうまくいくと次のようなアラートが表示されます。
![2021-01-25 221317.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/3e972699-50c7-2888-5e82-de60d8ea94f9.png)
アラートの内容は、クラスライブラリなので単独では実行・検証ができないという意味だと思います。

うまくいっていれば、この段階で、DLLとその関連ファイルが作成されて、レジストリにも登録されている状態となっています。

# 4. VBAでの実行

## 4-1. 参照設定

VBAが使えれば何でも良いのですが、ここではExcelからDLLを呼び出してみます。
テスト用に「マクロ有効ブック(*.xlsm)」を作成して、VBAメニューの「挿入」から標準モジュールを1つ作成します。
![2021-02-02 211941.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/5c1492f0-9a1b-d03f-6630-4609d22d6948.png)

次の図の青枠の部分にモジュールが1つ作成されています。
そして、メニュー「ツール」から参照設定を開きます。
![2021-02-02 212221.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/6828cfe5-495e-dc78-3d50-e5b1bd786741.png)

参照設定のダイアログ中「参照可能なライブラリファイル」を探すと、赤枠のところに先ほど作成した「MailKitLibrary」が登録されています。
これを選択してOKボタンを押します。
![2021-02-03 061119.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/3268cb0f-65c2-85c1-0577-48e30d2155f0.png)
なお、ダイアログの下の方の「場所」の部分に、作成したDLLのある場所が表示されます（カーソルを合わせると全てのディレクトリが表示されます）。
配布するときに必要なDLLファイルなどは、このディレクトリに保存されていますので、この場所も把握しておいてください。

## 4-2. VBAのソースコードを記載

さて、作成した標準モジュール「Module1」に、テスト用のコードを書いていきます。

当然ですが、「差出人および宛先の情報」、「SMTPサーバのURLとポート番号」、「メールアカウントとパスワード」、「添付ファイルの[MimeType](https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)とディレクトリ」は、実際のものを書かないと送信できませんのでご注意ください。

```vb
Sub MailKitTest()
    Dim objMail As New MailKitLibrary.MailKitClass

    Dim fromAddress(1) As String
    fromAddress(0) = "XXXXXXXXXX@ybb.ne.jp" '差出人のアドレス
    fromAddress(1) = "t-yama" '差出人の表示名
    Dim toAddress(1, 0) As String
    toAddress(0, 0) = "XXXXXXXXXX@XXX.ne.jp" '宛先のアドレス
    toAddress(1, 0) = "" '宛先の表示名（何も指定しない場合は空文字）
    Dim ccAddress(1, 0) As String
    ccAddress(0, 0) = "XXXXXXXXXX@outlook.jp" 'CCのアドレス
    ccAddress(1, 0) = "" 'CCの表示名（何も指定しない場合は空文字）
    Dim bccAddress(1, 0) As String
    bccAddress(0, 0) = "" 'BCCのアドレス（何も指定しない場合は空文字）
    bccAddress(1, 0) = "" 'BCの表示名（何も指定しない場合は空文字）
    
    Dim server As String: server = "ybbsmtp.mail.yahoo.co.jp" 'SMTPサーバのURL（使用するメールによって異なる）
    Dim port As Long: port = 465 'SMTPサーバのポート番号（使用するメールによって異なる）
    Dim account As String: account = "XXXXXXXXXX" '差出人のアカウント
    Dim password As String: password = "XXXXXXXXXX" '差出人のパスワード
    Dim subject As String: subject = "こんにちは" '件名
    Dim bodyText As String: bodyText = "テスト<b>メール</b>です" '本文を指定
    Dim mimeType As String: mimeType = "text/plain" 'MimeTypeを指定
    Dim filePath As String: filePath = "C:\Users\XXXXXXXXXX\Documents\Test.txt" '添付ファイルのフルパスを指定

    Call objMail.SendByMailKitAsync(fromAddress, toAddress, ccAddress, bccAddress, server, port, account, password, subject, bodyText, mimeType, filePath) 'MailKitで送信を実行
End Sub
```

コードが書けたら、実行するソースコードにカーソルを当てた上で、三角の実行ボタンを押します。
![2021-02-02 215836.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/0da22bb6-8ed8-bffe-e471-10da6083489e.png)
無事に、メールが送信されれば成功です。

手元では、**Outlookメール**、**Gmail**、**Yahooメール**で試しましたが、どのアドレスでも問題なく送信できました。

## 4-3. GUIDの確認（参考）

参考までに、DLLのGUIDの確認方法を書いておきます。
VBAの標準モジュールに次のように書きます。

```vb
Sub ReferencesSample()
    Dim ref As Variant
    For Each ref In ActiveWorkbook.VBProject.References
        Debug.Print ref.Name & ", " & ref.GUID
    Next
End Sub
```

実行すると、参照ライブラリ名とGUIDが表示されます。

```:イミディエイトウィンドウ
VBA, {000204EF-0000-0000-C000-000000000046}
Excel, {00020813-0000-0000-C000-000000000046}
stdole, {00020430-0000-0000-C000-000000000046}
Office, {2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}
Outlook, {00062FFF-0000-0000-C000-000000000046}
MailKitLibrary, {7FCC6104-16CE-4E54-9A00-33A5FF6C424E}
```

最後の1行が今回作成したDLLです。
GUIDが、Visual Studioで確認した`7FCC6104-16CE-4E54-9A00-33A5FF6C424E`と一致していることが分かります。

# 5. 作成したDLLの配布（他のPCでの実行）

基本的なことは「[VBAから扱えるDLLをC#で書いてみる。](https://www.ka-net.org/blog/?p=5464)」のサイトに丁寧に説明がされています。
こちらでも、順を追って書いておきます。

## 5-1. 配布用のDLLの作成

管理者としてVisual Studioを立ち上げて、作成したプロジェクトを開きます。
今度は**Release**構成にしてビルドを実行します（Debug構成で作成しても[大丈夫かも](https://tekk.hatenadiary.org/entry/20120524/1337873495)しれませんが、一般的な手順でやっておきます）。
![2021-02-02 223549.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/6d1c8bdb-3ab4-08e9-6b22-72c3bb32aae0.png)

作成したファイルのフォルダを開きます。
赤枠のところからプロジェクトのフォルダを開いて「bin」→「x64」→「Release」の順でフォルダを開きます（私の環境の場合）。
![2021-02-02 224132.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/ac19a9f5-4f01-4029-dc8b-8d12c37b5706.png)
私の手元では、ディレクトリは`C:\Users\ユーザー名\source\repos\MailKitLibrary\MailKitLibrary\bin\x64\Release`となっています。

フォルダの中には14個のファイルが入っています。
![2021-02-02 224744.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/29c6a40e-e568-d686-e342-d38e15fe3e73.png)
これをそのまま、VBAを書いたExcelとともに配布します。

## 5-2. レジストリにDLLを登録（RegAsm.exe）

### 5-2-1. DLL関連ファイルの保存

まずは、配布先のPCのどこかに、**DLL関連のファイルをReleaseフォルダごと保存**します。
ここでは、`C:\SourceDll`というフォルダを作って、そこにReleaseフォルダを保存しました。

### 5-2-2. レジストリへの登録方法

次は、レジストリへの登録です。
コンパイルを実行したPCにおいては自動的にレジストリに登録されますが、**配布先のPCにおいては別途レジストリに登録**をする必要があります。
具体的には、**[RegAsm.exe（アセンブリ登録ツール](https://docs.microsoft.com/ja-jp/dotnet/framework/tools/regasm-exe-assembly-registration-tool)）**を使用して登録をすることになります。

RegAsm.exeは、32ビット用と64ビット用で異なる場所に入っています。
私の手元では、それぞれ2つずつの計4個のRegAsm.exeがありましたが、ここでは`v4.0`となっているものを使います（次のとおり）。

＜32ビット用＞
`C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe`

＜64ビット用＞
`C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe`

作成した**DLL**および**使用する環境**に合わせて、32ビットか64ビットかを選択しますが、ここでは64ビットで進めます。

ここでは、どのWindows PCにも入っているコマンドプロンプトで登録します。
登録するコマンドは次のようになります。

＜**登録するとき**＞
`"RegAsm.exeのディレクトリ" "DLLファイルのディレクトリ" /tlb /codebase`

＜**解除するとき**＞
`"RegAsm.exeのディレクトリ" "DLLファイルのディレクトリ" /tlb /u`

具体的に次のとおりです（64ビットの場合）。

```
登録するときのコマンド
C:\WINDOWS\system32>"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" "C:\SourceDll\Release\MailKitLibrary.dll" /tlb /codebase

解除するときのコマンド
C:\WINDOWS\system32>"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" "C:\SourceDll\Release\MailKitLibrary.dll" /tlb /u
```

### 5-2-3. コマンドプロンプトで登録

実際にやってみます。
レジストリを変更するため、**管理者権限**でコマンドプロンプトを立ち上げます（`右クリック`→`その他`→`管理者として実行`）。
次のようにコマンドを打ち込みます。
![2021-02-02 232243.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/c2f7cad4-1847-c838-6a00-e696954fa83a.png)

Enterを押すと次のように表示されて登録が完了します。
![2021-02-02 232305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/58e2bc35-046b-bf6f-5cf3-34ac1ebb675c.png)

これで、VBAの参照設定を開くと、確かに作成したDLLファイルがライブラリとして表示されています。
![2021-02-02 232534.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/310d0d65-5121-0ae9-2a37-b07367f39978.png)
下の「場所」のところも、先ほど作成したフォルダ`C:\SourceDll\Release\MailKitLibrary.dll`となっているのが分かります。

チェックを入れてOKボタンを押せば、配布先のPCでもMailKitを使用してメールを送ることができるようになります。

### 5-2-4. レジストリの解除（参考）

一応、解除までやっておきます。
解除をする場合は、先ほど示した、`C:\WINDOWS\system32>"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" "C:\SourceDll\Release\MailKitLibrary.dll" /tlb /u`というコマンドを打って実行します。

次のような表示となり、レジストリが解除されます。
![2021-02-02 234326.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551412/68b3f4a4-ef0b-82b3-5ae2-073cd7fde619.png)

# さいごに

一応、メールの送信まではできるようになりましたが、[インテリセンス](https://e-words.jp/w/%E3%82%A4%E3%83%B3%E3%83%86%E3%83%AA%E3%82%BB%E3%83%B3%E3%82%B9.html)については、エラーが出てうまくいかなかったのでここでは触れていません（オープンソースは無理なのでしょうかね？）。

試してはいませんが、[PowerShell](https://ja.wikipedia.org/wiki/PowerShell)を使う方法もあると思いますので、また後日やってみようかと思います。