Outlookで選択したメールの宛先を抽出するマクロ関数です。選択したメールの親フォルダに応じて送信者と受信者を判定し、適切な宛先名を抽出します。メール文頭、送信者表記名(Senderプロパティ)、TOメアド及び、メール親フォルダそれぞれを判定条件し、意図した宛先抽出が可能です。
また、DearとFromをキーワードに英語の場合は「Eng 名前」として抽出することでその後の処理で活用できます。https://gakuhenn.com/vba-chatgptapi-outlookmail-system/で紹介したメール文作成システムのようなマクロで活用できます。
・挙動
対象のメールを選択した状態でプロシージャを実行します。親フォルダ(受信フォルダ、曹仁済みフォルダ)及び、メール文頭の内容から、宛先●●さんを取得します。

受信ボックスではなく、送信済みボックス上のメールに対して実行した場合、送信者は田中=あなたになるため、●●は佐藤さんとして抽出されます。

・コード
➤選択メールの宛先を表示するプロシージャこちら
Option Explicit
Sub fChkParentFolder_Sub()
Dim olApp As Outlook.Application
Dim olMail As Outlook.MailItem
Dim olSelection As Outlook.Selection
Dim Mailbody As String
Dim olFolder As Folder
Dim parentFolder As Object
Dim folderPath As String
Dim MSenderOrMReceiver As String
' Outlook から選択メールを取得
Set olApp = Outlook.Application
Set olSelection = olApp.ActiveExplorer.Selection
If olSelection.count = 0 Then
MsgBox "メールが選択されていません。"
Exit Sub
End If
If Not TypeOf olSelection.Item(1) Is Outlook.MailItem Then
MsgBox "選択されたアイテムはメールではありません。"
Exit Sub
End If
Set olMail = olSelection.Item(1)
Mailbody = olMail.body
Set olFolder = olMail.Parent
folderPath = olFolder.Name
Set parentFolder = olFolder
Do While Not parentFolder.Parent Is Nothing
Set parentFolder = parentFolder.Parent
If TypeOf parentFolder Is Outlook.Folder Then
folderPath = parentFolder.Name & "\" & folderPath
Else
Exit Do
End If
Loop
If InStr(1, folderPath, "受信", vbTextCompare) > 0 Then
MSenderOrMReceiver = "MSender"
ElseIf InStr(1, folderPath, "送信", vbTextCompare) > 0 Then
MSenderOrMReceiver = "MReceiver"
Else
MSenderOrMReceiver = "MSender"
End If
' 名前抽出を実行
Dim result As String
result = fExtractNameInMail(MSenderOrMReceiver, Mailbody, olMail, "英語であなたの苗字", "日本語であなたの苗字")
MsgBox "宛先: " & result
End Sub
Function fExtractNameInMail(MSenderOrMReceiver As String, Mailbody As Variant, mailsent As Outlook.MailItem, YouLstName As String, YouLstNameJp As String) As String
Dim olApp As Outlook.Application
Dim olMail As Outlook.MailItem
Dim olSelection As Selection
Dim bodyText As String
Dim MailSender As String
Dim lines As Variant
Dim namefrom As String
Dim KeywordsArray() As Variant
Dim MailSenderAdr As String
bodyText = Mailbody
' 本文を改行ごとに分割
lines = Split(bodyText, vbCrLf)
If InStr(1, MSenderOrMReceiver, "MSender", vbTextCompare) > 0 Then
KeywordsArray = Array("です", "from", ",")
ElseIf InStr(1, MSenderOrMReceiver, "MReceiver", vbTextCompare) > 0 Then
KeywordsArray = Array("です", "Dear", ",")
End If
' 先頭3行を結合(4行)
Dim i As Integer, namefrombuf As String
For i = LBound(lines) To Application.WorksheetFunction.Min(UBound(lines), 4)
If i >= 0 Then
namefrom = namefrom & " " & lines(i)
namefrombuf = namefrom
If InStr(1, namefrom, "です", vbTextCompare) Or InStr(1, namefrom, "申します", vbTextCompare) Then
i = 100
namefrom = Trim(namefrom)
Exit For
ElseIf InStr(1, namefrom, "from", vbTextCompare) Then
namefrom = Trim(namefrom)
i = 101
Exit For
'Fromが改行されている場合
ElseIf InStr(1, namefrom, ",", vbTextCompare) Then
namefrom = Trim(namefrom)
Dim ii As Long
For ii = i To 2
namefrom = namefrom & " " & lines(ii + 1)
namefrombuf = namefrom
If InStr(1, namefrom, "from", vbTextCompare) Then
i = 101
namefrom = Trim(namefrom)
Exit For
End If
Next
Exit For
End If
End If
Next i
'メール本文が「●●さん、●●です」以外で宛先抽出できない場合
'送信者表示名,シート上のあなたの名前から宛先名を判断
If i <> 101 And i <> 100 Then
'あなたの名前がnameinmail=本文冒頭に「Dear あなたの名前」のように入っている場合、MailsenderNameを宛先に
If InStr(1, namefrom, YouLstName, vbTextCompare) > 0 Or InStr(1, namefrom, YouLstNameJp, vbTextCompare) > 0 Then
MailSenderAdr = mailsent.SenderName
Else
'それ以外の場合To宛先の人を宛先にする
MailSenderAdr = mailsent.To
End If
If IsJPTexts(namefrom, "0.1") Then
fExtractNameInMail = GetLastNameInMailAdr(MailSenderAdr, "ja")
Else
fExtractNameInMail = GetLastNameInMailAdr(MailSenderAdr, "en")
End If
Exit Function
End If
'’’’’’’’’’’’’’’’’’’’’’’’’’' 英語メールの場合処理追加必要’’’’’’’’’’’’’’’’’’’’’’’’’
'MsgBox namefrom
If i = 101 And InStr(1, MSenderOrMReceiver, "MSender", vbTextCompare) > 0 Then
fExtractNameInMail = Mid(namefrom, InStr(1, namefrom, "from", vbTextCompare) + 5)
Exit Function
ElseIf InStr(1, namefrom, "Dear", vbTextCompare) > 0 And InStr(1, namefrom, "from", vbTextCompare) > 0 Then
fExtractNameInMail = Mid(namefrom, InStr(1, namefrom, "Dear", vbTextCompare) + 5, InStr(1, namefrom, "san", vbTextCompare) - (InStr(1, namefrom, "Dear", vbTextCompare) + 5))
Exit Function
ElseIf InStr(1, namefrom, "Dear", vbTextCompare) > 0 And InStr(1, namefrom, ",", vbTextCompare) > 0 Then
' 送信者に送りたいときで、from送信者のような記載もない場合の名前抽出は例外的記述の多さにより困難
fExtractNameInMail = "EngName "
Exit Function
ElseIf InStr(1, namefrom, "san", vbTextCompare) > 0 Or InStr(1, namefrom, "Dear", vbTextCompare) > 0 Then
fExtractNameInMail = "EngName "
Exit Function
End If
Dim TrimedNamefrom As String
KeywordsArray = Array(" ", " ", "、", vbCrLf, vbLf, vbCr, vbTab)
TrimedNamefrom = namefrom
TrimedNamefrom = Removekeywords(TrimedNamefrom, KeywordsArray)
TrimedNamefrom = CompareToExtract(MSenderOrMReceiver, namefrom, TrimedNamefrom)
'Debug.Print TrimedNamefrom
KeywordsArray = Array("です。", "です", "。", "、", "さん", " 様", " 様", " 課長", " 課長", " 部長", " 部長")
'Debug.Print Removekeywords(TrimedNamefrom, KeywordsArray)
TrimedNamefrom = Removekeywords(Trim(TrimedNamefrom), KeywordsArray)
If InStr(1, MSenderOrMReceiver, "MSender", vbTextCompare) > 0 Then
TrimedNamefrom = Mid(TrimedNamefrom, InStrRev(TrimedNamefrom, " ", , vbTextCompare) + 1)
End If
fExtractNameInMail = Trim(TrimedNamefrom)
'MsgBox fExtractNameInMail
End Function
Function Removekeywords(text As String, removewords As Variant) As String
Dim patterns As Variant
Dim i As Integer
' 削除する文字列のリスト
patterns = removewords
' 配列をループして置換
For i = LBound(patterns) To UBound(patterns)
text = Replace(text, patterns(i), "")
Next i
' 結果を返す
Removekeywords = text
End Function
Function CompareToExtract(MSenderOrMReceiver As String, original As String, trimmed As String) As String
Dim i As Long
Dim lengthOriginal As Long
Dim lengthTrimmed As Long
' 元の文字列と削除後の文字列の長さを取得
lengthOriginal = Len(original)
lengthTrimmed = Len(trimmed)
' 短い方の長さまで比較
For i = 1 To Application.WorksheetFunction.Min(lengthOriginal, lengthTrimmed)
' 先頭から異なる文字が見つかった場合
If Mid(original, i, 1) <> Mid(trimmed, i, 1) Then
If InStr(1, MSenderOrMReceiver, "MSender", vbTextCompare) > 0 Then
' その位置から文末までの文字列を削除
CompareToExtract = Mid(original, i)
Exit Function
ElseIf InStr(1, MSenderOrMReceiver, "MReceiver", vbTextCompare) > 0 Then
' 先頭からその位置までの文字列を削除
CompareToExtract = Left(original, i)
Exit Function
Else
' 先頭からその位置までの文字列を削除
CompareToExtract = Mid(original, i)
Exit Function
End If
End If
Next i
' 異なる部分が見つからない場合
CompareToExtract = original
End Function
Function GetLastNameInMailAdr( _
Mailaddress As String, _
Optional lang_JPorEN As String = "en" _
) As String
Dim eng As String
Dim jp As String
Dim pos1 As Long, pos2 As Long
Dim result As String
Dim hasBracket As Boolean
' ()位置
pos1 = InStr(Mailaddress, "(")
pos2 = InStr(Mailaddress, ")")
hasBracket = (pos1 > 0 And pos2 > pos1)
' =========================
' ()があるケース ()の中に日本語名がある表式を想定
' =========================
If hasBracket Then
' 英語部分
eng = Trim(Left(Mailaddress, pos1 - 1))
' 日本語部分
jp = Mid(Mailaddress, pos1 + 1, pos2 - pos1 - 1)
If LCase(lang_JPorEN) = "jp" Or LCase(lang_JPorEN) = "ja" Then
jp = Replace(jp, " ", " ")
GetLastNameInMailAdr = Split(Trim(jp), " ")(0)
Else
result = Split(Trim(eng), " ")(0)
GetLastNameInMailAdr = StrConv(LCase(result), vbProperCase)
End If
' =========================
' ()が無いケース
' =========================
Else
' 英語(先頭単語)
On Error Resume Next
Mailaddress = Mid(Mailaddress, 1, InStr(1, Mailaddress, "@", vbTextCompare) - 1)
eng = Mailaddress
On Error GoTo 0
' < より前だけ使う(メール部分除去)
If InStr(eng, "<") > 0 Then
eng = Left(eng, InStr(eng, "<") - 1)
End If
result = Split(Trim(eng), " ")(0)
GetLastNameInMailAdr = StrConv(LCase(result), vbProperCase)
'日本語指定されている場合でメール文から日本語取得できない場合は翻訳
'If LCase(lang_JPorEN) = "jp" Or LCase(lang_JPorEN) = "ja" Then
'On Error Resume Next
' GetLastNameInMailAdr = TranslateTexts_DefJPandEN(GetLastNameInMailAdr, "en", "jp")
'On Error GoTo 0
'End If
End If
End Function
Function GetSMTPAddress(mail As Outlook.MailItem) As String
Dim sender As Outlook.AddressEntry
Dim exchUser As Outlook.ExchangeUser
Set sender = mail.sender
If sender Is Nothing Then Exit Function
' Exchangeユーザーの場合
If sender.Type = "EX" Then
Set exchUser = sender.GetExchangeUser
If Not exchUser Is Nothing Then
GetSMTPAddress = exchUser.PrimarySmtpAddress
Else
GetSMTPAddress = ""
End If
Else
' 通常SMTP
GetSMTPAddress = mail.SenderEmailAddress
End If
End Function
単純に選択メール送信者のメアドを取得する場合は、Olmailのsenderプロパティーを取得することで、メールの送信者を取得できます。この場合、exchangeの表記設定によっては和英が混在していない場合があり、和文の名前が抽出できないこともあります。
メール文頭での名前取得を基本に、どのメールでも宛先取得ができるように、今スクリプトでは、メールでの文頭、送信者プロパティ、TOメアド及び、選択メールのボックスを条件に宛先を取得しています。
メール文頭が「○○さん ●●です。」の場合選択したメールぼっくに応じて○○か●●が取得されます。
メール文頭が「○○様/部長」や「●●と申します。」などのように異なる表記であっても、送信者の表記名から(Oultook上で表示されているメアド表示)形式から和英双方の苗字を取得可能です。
・ポイント機能
・選択メールの親フォルダ:ParentFolderの取得
・選択メールのボックスに応じた宛先抽出
ParentFolderの取得

Outlookのメールはそれぞれに対してウィンドウズファイルと同じようにパスの情報があります。そのルートフォルダになる場所に今回使用する受信ボックスと、送信済みボックスの二つの場所があります。今回は送信済みメールに返信するのであれば、メールの宛先を宛先とし、受信ボックスメールに返信するのであれば、メール送信者を宛先にします

そこで、parentFolder変数に選択したメールの親フォルダを親フォルダがなくなるまでDo whileで継続します。そうして得られるパスには、受信ボックスと、送信済みフォルダの文字が入ったパスになります。
これを利用し、選択したメールが受信か送信済みボックスどちらか判定に使います。Instrで単純に一部ワードを検索し含まれているか判定します。

受信ボックスならMSender、送信済みボックスならMReceiver、それ以外はMSenderとして関数に代入します。これを宛先抽出関数で使用します。
選択メールのボックスに応じた宛先抽出
宛先抽出関数ではいくつかの関数を使用します。必要なのは、MSenderかMReceiverかと、選択したメールの本文です。まず、全体文を改行ごとに配列化します。

そして、メール冒頭から検索し、「です」か「from」がある行まで抽出します(○○さん ●●です/ Dear Mr. ○○, from ●● のような文頭を想定)。
それ以外の場合で、
・「です」のみが存在する場合
・文頭無し&本文のみの場合に対しても、分岐処理により宛先を適切に抽出可能です。
メール文頭が「○○さん ●●です/ Dear Mr. ○○, from ●● のような場合」
です/from行を取得することで宛先と送信者が含まれた一行を得られるというわけです。

まず英語のメールであるか判断処理をします。Dear,Fromというキーワードが入っていれば、英文のメールであると判断し、宛先となる部分を抜き出します。
MSenderorReceiverがSenderであれば、送信者に送るということなので、From以降の●●を宛先として、「Eng ●●」の形で変数に格納します。これにより、後々Eng を削除し宛先のみを抽出します。

もし上記の英語要処理に当てはまらない場合は日本語の文と見なします。「○○さん ●●です」の文から、○○、●●を抽出するために元の文章と調整した文章を用意します。後者は、空欄や句読点を取り除いたものです。Removekeywords関数で指定したKeywordsArrayに入った値をすべて削除します。

二つの文章および、MSenderorMReceiverを引数に、CompareToExtraxt関数を実行します。関数では、二つの文字の先頭および中部から文字を比較し、異なる箇所があった時点でその場所を抜き出します。
「○○さん ●●です」から「○○さん●●です」になり、空欄の箇所が抜出のポイントとなります。

その後取得した値をさらに形成します。上記のままだと敬称等がついており、名前だけの抽出ができていません。そこで再度RemoveKeywords関数で余分な文字を指定し、削除します。今回は「です。、さん」などを削除しています。これにより純粋な宛先名のみ取得することができます。
それ以外の文頭ケース:「です」のみが存在、本文から始まる
送信者表示名(SenderName)orメールアドレスから宛先名を判断し、①送信者表示名か②TOメアドを基に置き換えます。
①送信者表示名はTOメアドの表示と異なります。 これは管理者の設定値により表示方法が異なる為です。
| プロパティ | 備考 |
|---|---|
| SenderName | 表示名( <>は含まれない) To / CCのプロパティも同じ |
| SenderEmailAddress | 技術的なメールアドレス(SMTP) |
Sendernameプロパティは会社によって設定が変わります。今回は「英語名前(日本語名前)」というメアド設定されている前提にしています。つまり「Suzuki Taro(鈴木太郎).com」のような表記
SenderEmailAddressはそのまま使用すると、メアド以外の情報も含めてまとめて取得される場合があります。「/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP …」のような値です。
上記のような値が取得される場合、ExchangeUserを経由してメアド取得する必要があります。そこでGetSMTPAddress関数で、通常のSMTPかどうか判定しメアド取得しています。
これにより社内exchangeシステムでの取得値で、外部メールでもメアドだけを取得可能です。
②TOメアドを元に宛先とする場合、複数の宛先が入ってしまい送信者を確実に特定できない場合もあります。
極力TOメアドで置き換えを避けるため、本文にあなたの和英苗字が入っていれば、そのメール送信者を返信対象にすると解釈し、メール表示名を宛先に置き換えます。

これはFunction fExtractNameInMail関数の第4、5引数 :YouLstName As StringとYouLstNameJp As Stringに指定した値が使用されます。今回は静的な苗字を設定していますが、シート上の値を格納するなどして動的に動作するようにしてください。
それでもToメアドから宛先を判定する場合、下記関数の元で、和英どちらかの苗字か、メールから名前全体を取得します。

Tanaka Taro (田中 太郎)@abc.comのようなメアド標識の場合、引数と括弧を元にTanakaあるいは田中が抽出されます。
カッコが無いのメアド形式の場合は、@までを取得してメアドでの名前を取得します。英語のみの場合、一文字目は大文字として取得します。
また、Toメアドで宛先抽出した際に、和文混合ではないため英語名のみ取得できる場合があります。その際は下記部分TranslateTects_DefJPandENで翻訳可能です。

翻訳関数ではGAS,GoogleCloud翻訳API,AzureAPIどれかを使用可能です。翻訳関数は下記記事で紹介しています。
・応用:動的メール作成
今マクロを活用することで、選択したメールに応じて宛先を置き換えたメール作成が可能です。さらに、キーワードによる置き換えや自動翻訳機能を付けることで、ただのテンプレメール作成にとどまらない、柔軟なメール作成が即座に可能になります。

