コンテンツへスキップ

VBAでメール送付

Excelマクロ(vba)でSMTPを介して自動的にメール送付できると何かと便利です。

BASP21でメールを送るのが有名ですが、32bitのExcelでしか動かないのが難点です。

CODを利用すれば64bitでも動くので、そのコードを記載しておきます。

ここのコードをベースにしていますが、呼び出しをシンプルにするために全体的に改良しています。

活用方法

  1. SendMailCDOというクラスを作り、中に以下のコードを貼り付けます。
'******************************************************************
'■ プロパティ定義
'******************************************************************

Private strFromName As String               '差出人名(String)
Private strFromAddr As String               '差出人アドレス(String)
Private vntToName As Variant                '宛先名(Variant)
Private vntToAddr As Variant                '宛先アドレス(Variant)
Private vntCCName As Variant                'CC名(Variant)
Private vntCCAddr As Variant                'CCアドレス(Variant)
Private vntBCCName As Variant               'BCC名(Variant)
Private vntBCCAddr As Variant               'BCCアドレス(Variant)
Private swOwnerBCC As Boolean               '差出人BCC指定(Boolean)
Private strSubj As String                   '件名(String)
Private strBody As String                   '本文(String)
Private strSign As String                   '署名(String)
Private vntAttachFile As Variant            '添付ファイル名(Variant)
Private strSMTP As String                   'SMTPサーバアドレス(String)
Private intPort As Integer                  'ポート№(Integer)
Private intTimeOut As Integer               'タイムアウト値(Integer)
Private strLanguageCode As String           '文字コード指定(String) 有効値: utf-8, shift-jis, iso-2022-jp, euc-jp
Private intAuthenticate As Integer          '認証指定(Integer) 有効値: 0=無し、1=有り
Private blnUseSSL As Boolean                'SSL使用(Boolean)
Private g_strSendUserName As String         '認証ユーザーID(String)
Private g_strSendPassword As String         '認証パスワード(String)
Private g_strErrMSG As String               'エラーメッセージ(String)


'******************************************************************
'■ プロパティ受付
'******************************************************************

'差出人名(String)
Friend Property Let prpFromName(ByVal Value As String)
    strFromName = Value
End Property

'差出人アドレス(String)
Friend Property Let prpFromAddr(ByVal Value As String)
    strFromAddr = Value
End Property

'宛先名(Range)
Friend Property Let prpToName(ByVal Value As Range)
    vntToName = GetCellsValue(Value)
End Property

'宛先アドレス(Variant)
Friend Property Let prpToAddr(ByVal Value As Range)
   vntToAddr = GetCellsValue(Value)
End Property

'CC名(Variant)
Friend Property Let prpCCName(ByVal Value As Range)
   vntCCName = GetCellsValue(Value)
End Property

'CCアドレス(Variant)
Friend Property Let prpCCAddr(ByVal Value As Range)
   vntCCAddr = GetCellsValue(Value)
End Property

'BCC名(Variant)
Friend Property Let prpBCCName(ByVal Value As Range)
   vntBCCName = GetCellsValue(Value)
End Property

'BCCアドレス(Variant)
Friend Property Let prpBCCAddr(ByVal Value As Range)
   vntBCCAddr = GetCellsValue(Value)
End Property

'差出人BCC指定(Boolean)
Friend Property Let prpOwnerBCC(ByVal Value As Boolean)
   swOwnerBCC = Value
End Property

'件名(String)
Friend Property Let prpSubj(ByVal Value As String)
   strSubj = Value
End Property

'本文(String)
Friend Property Let prpBody(ByVal Value As String)
   strBody = Value
End Property

'署名(String)
Friend Property Let prpSign(ByVal Value As String)
   strSign = Value
End Property

'添付ファイル名(Variant)
Friend Property Let prpAttachFile(ByVal Value As Range)
   vntAttachFile = GetCellsValue(Value)
End Property

'SMTPサーバ(String)
Friend Property Let prpSMTP(ByVal Value As String)
    strSMTP = Value
End Property

'ポート№(Integer)
Friend Property Let prpPort(ByVal Value As Integer)
    intPort = Value
End Property

'タイムアウト値(Integer)
Friend Property Let prpTimeOut(ByVal Value As Integer)
    intTimeOut = Value
End Property

'文字コード指定(String) 有効値: utf-8, shift-jis, iso-2022-jp, euc-jp
Friend Property Let prpLanguageCode(ByVal Value As String)
    strLanguageCode = Value
End Property

'認証指定(Integer) 有効値: 0=無し、1=有り
Friend Property Let prpAuthenticate(ByVal Value As Integer)
    intAuthenticate = Value
End Property

'SSL使用(Boolean)
Friend Property Let prpUseSSL(ByVal Value As Boolean)
    blnUseSSL = Value
End Property

'認証ユーザーID(String)
Friend Property Let prpSendUserName(ByVal Value As String)
    g_strSendUserName = Value
End Property

'認証パスワード(String)
Friend Property Let prpSendPassword(ByVal Value As String)
    g_strSendPassword = Value
End Property

'エラーメッセージ(String)
Friend Property Get prpErrMSG() As String
    prpErrMSG = g_strErrMSG
End Property


'******************************************************************
'■ プロパティデフォルト値
'******************************************************************
'パラメータを受け取らなかった場合の初期値

Private Sub Class_Initialize()
    swOwnerBCC = False                  '差出人BCC指定(Boolean)
    vntAttachFile = ""                  '添付ファイル名(Variant)
    strSMTP = ""                        'SMTPサーバ(String)
    intPort = 587                       'ポート№(Integer)
    intTimeOut = 20                     'タイムアウト値(Integer)
    strLanguageCode = "utf-8"           '文字コード指定(String) 有効値: utf-8, shift-jis, iso-2022-jp, euc-jp
    intAuthenticate = 1                 '認証指定(Integer) 有効値: 0=無し、1=有り
    blnUseSSL = False                   'SSL使用(Boolean)
    g_strErrMSG = ""                    'エラーメッセージ(String)
End Sub


'******************************************************************
'■ メール送信(メイン処理)
'******************************************************************

Friend Function SendMail() As Boolean
    SendMail = False
    
    'プロパティ項目チェック
    If CheckProperty() = False Then Exit Function
    
    '氏名とメールアドレスの結合(複数メールアドレス可)
    Dim strMailFrom As String                                       ' 差出人
    strMailFrom = JointMailAddress(strFromName, strFromAddr)
    Dim strMailTo As String                                         ' 宛先
    strMailTo = JointMailAddress(vntToName, vntToAddr)
    Dim strMailCc As String                                         ' CC
    strMailCc = JointMailAddress(vntCCName, vntCCAddr)
    Dim strMailBcc As String                                        ' BCC
    If swOwnerBCC Then
        strMailBcc = JointMailAddress(vntBCCName, vntBCCAddr) & "," & JointMailAddress(strFromName, strFromAddr)
    Else
        strMailBcc = JointMailAddress(vntBCCName, vntBCCAddr)
    End If
    
    '件名から改行コードの削除
    strSubj = Replace(Trim(strSubj), vbCrLf, "")
    strSubj = Replace(Trim(strSubj), vbCr, "")
    strSubj = Replace(Trim(strSubj), vbLf, "")
    
    '本文の改行コードを統一し最後に改行を追加
    strBody = Replace(Trim(strBody), vbCrLf, vbLf)
    strBody = Replace(strBody, vbCr, vbLf)
    If Right(strBody, 2) <> vbLf Then
        strBody = strBody & vbLf
    End If
    
    '署名がある場合は本文に追加
    If strSign <> "" Then
        If Right(strBody, 4) <> vbLf & vbLf Then
            strBody = strBody & vbLf
        End If
        strBody = strBody & strSign
    End If
    
    'メール送信
    Dim objCDO As New CDO.Message
    On Error Resume Next
    With objCDO
        With .Configuration.Fields
            .Item(cdoSendUsingMethod) = cdoSendUsingPort
            .Item(cdoSMTPServer) = strSMTP                      'SMTPサーバ名
            .Item(cdoSMTPServerPort) = intPort                  'ポート№
            .Item(cdoSMTPConnectionTimeout) = intTimeOut        'タイムアウト
            .Item(cdoLanguageCode) = strLanguageCode            '文字コード指定
            .Item(cdoSMTPAuthenticate) = intAuthenticate        '認証指定
            If intAuthenticate = 1 Then
                .Item(cdoSendUserName) = g_strSendUserName      '認証ユーザー
                .Item(cdoSendPassword) = g_strSendPassword      '認証パスワード
                .Item(cdoSMTPUseSSL) = blnUseSSL                'SSL指定
            End If
            .Update
        End With
        .MimeFormatted = True
        .Fields.Update
        .From = strMailFrom                                     '送信者
        .To = strMailTo                                         '宛先
        If strMailCc <> "" Then .CC = strMailCc                 'CC
        If strMailBcc <> "" Then .BCC = strMailBcc              'BCC
        .Subject = strSubj                                      '件名
        .TextBody = strBody                                     '本文
        .TextBodyPart.Charset = strLanguageCode                 '文字コード指定
        If IsArray(vntAttachFile) Then                          '添付ファイルの登録(複数対応)
            Dim lngIx As Long
            Do While lngIx <= UBound(vntAttachFile)
                .AddAttachment Trim(vntAttachFile(lngIx))
                lngIx = lngIx + 1
            Loop
        ElseIf vntAttachFile <> "" Then
            .AddAttachment Trim(vntAttachFile)
        End If
        .Send
    End With
    Set objCDO = Nothing
    
    'エラー判定
    If Err.Number <> 0 Then
        g_strErrMSG = "メール送信に失敗しました。" & vbCrLf & Err.Description
    End If
    On Error GoTo 0
    
    '成否判定を返す
    SendMail = g_strErrMSG = ""
    
End Function

'******************************************************************
'■ 関数
'******************************************************************

'------------------------------------------------------------------
' 関数処理:プロパティチェック
' 引数  :(なし)
' 返り値 :処理成否(Boolean)
'------------------------------------------------------------------

Private Function CheckProperty() As Boolean
    CheckProperty = False
    
    '差出人チェック
    If strFromAddr = "" Then
        g_strErrMSG = "「差出人アドレス」が指定されていません。"
        Exit Function
    End If
    
    ' 宛先チェック
    If IsArray(vntToAddr) = False Then
        If vntToAddr = "" Then
            g_strErrMSG = "「宛先アドレス」が指定されていません。"
            Exit Function
        End If
    End If
    
    '件名チェック
    If strSubj = "" Then
        g_strErrMSG = "「件名」が指定されていません。"
        Exit Function
    End If
    
    '本文チェック
    If strBody = "" Then
        g_strErrMSG = "「本文」が指定されていません。"
        Exit Function
    End If
    
    '添付ファイル存在チェック
    Dim objFso As New FileSystemObject
    '複数ファイルの場合
    If IsArray(vntAttachFile) Then
        Dim lngIx As Long
        Do While lngIx <= UBound(vntAttachFile)
            If objFso.FileExists(Trim(vntAttachFile(lngIx))) = False Then
                g_strErrMSG = "指定のファイルが実在しません。" & vbCrLf & Trim(vntAttachFile(lngIx))
                Exit Function
            End If
            lngIx = lngIx + 1
        Loop
    '単一ファイルの場合
    ElseIf vntAttachFile <> "" Then
        If objFso.FileExists(Trim(vntAttachFile)) = False Then
            g_strErrMSG = "指定のファイルが実在しません。" & vbCrLf & Trim(vntAttachFile)
            Exit Function
        End If
    End If
    Set objFso = Nothing

    '認証関連チェック
    If intAuthenticate = 1 Then
        If g_strSendUserName = "" Then
            g_strErrMSG = "「アカウント(詳細情報)」が指定されていません。"
            Exit Function
        End If
        If g_strSendPassword = "" Then
            g_strErrMSG = "「パスワード(詳細情報)」が指定されていません。"
            Exit Function
        End If
    End If
    
    CheckProperty = True
End Function


'------------------------------------------------------------------
' 関数処理:Range内のデータが1つであればStringに、複数であれば配列にする
' 引数  :Arg1 = セル範囲(Range)
'           Arg2 = 最終行(Long) *Optional
' 返り値 :処理成否(Boolean)
'------------------------------------------------------------------

Private Function GetCellsValue(ByRef objR As Range) As Variant

    '列取得
    Dim lngCol As Long
    lngCol = objR.Cells(1).Column

    '先頭行の取得
    Dim lngRowStart As Long
    lngRowStart = objR.Cells(1).Row
    
    '最終行の取得
    Dim lngRowEnd As Long
    lngRowEnd = lngRowStart + objR.Rows.Count - 1
    lngRowEnd = Cells(lngRowEnd + 1, lngCol).End(xlUp).Row
    
    '未入力の場合
    If lngRowEnd < lngRowStart Then
        GetCellsValue = ""
    '1件の場合
    ElseIf lngRowEnd = lngRowStart Then
        GetCellsValue = Trim(Cells(lngRowStart, lngCol).Value)
    '複数件の場合
    Else
        Dim tblText() As String         '配列
        ReDim tblText(0)
        Dim lngIx As Long: lngIx = -1   '配列index
        Dim strText As String           '確認するセルの値
        Dim lngRow As Long              '確認する列
        For lngRow = lngRowStart To lngRowEnd
            strText = Trim(Cells(lngRow, lngCol).Value)
            If strText <> "" Then
                lngIx = lngIx + 1
                ReDim Preserve tblText(lngIx)
                tblText(lngIx) = strText
            End If
        Next lngRow
        Select Case lngIx
            Case -1
                GetCellsValue = ""
            Case 0
                GetCellsValue = tblText(0)
            Case Else
                GetCellsValue = tblText
        End Select
    End If

End Function


'------------------------------------------------------------------
' 関数処理:氏名とメールアドレスを結合(複数の場合はカンマで区切る)
' 引数  :Arg1 = 名称(Variant)
'           Arg2 = アドレス(Variant)
' 返り値 :接合後アドレス(String)
'------------------------------------------------------------------

Private Function JointMailAddress(ByVal vntName As Variant, _
                                  ByVal vntEmail As Variant) As String
    Dim strName As String                       '名称
    Dim strEmail As String                      'アドレス
    
    'アドレスがRange配列(複数指定)の場合
    If IsArray(vntEmail) Then
        Dim lngIx As Long                       '配列index
        Dim lngIxMax1 As Long                   '配列index上限(名称)
        Dim lngIxMax2 As Long                   '配列index上限(アドレス)
        Dim strAddr As String                   '編集後アドレス
        strAddr = ""
        lngIxMax2 = UBound(vntEmail)
        ReDim tblAddr(lngIxMax2)
        '名称もRange配列(複数指定)か
        If IsArray(vntName) Then
            lngIxMax1 = UBound(vntName)
        Else
            lngIxMax1 = -1
        End If
        '配列を巡回
        Do While lngIx <= lngIxMax2
            strEmail = Trim(vntEmail(lngIx))
            '名称は要素数を判定してセット
            If lngIxMax1 >= lngIxMax2 Then
                strName = Trim(vntName(lngIx))
            Else
                strName = ""
            End If
            '2件目以降はカンマで区切る
            If strAddr <> "" Then
                strAddr = strAddr & ","
            End If
            'アドレスのみか
            If strName = "" Then
                strAddr = strAddr & strEmail
            Else
                strAddr = strAddr & strName & " <" & strEmail & ">"
            End If
            lngIx = lngIx + 1
        Loop
        JointMailAddress = strAddr
    
    'アドレスが単一の場合
    Else
        strName = ""
        strEmail = ""
        'Variant項目チェック
        If VarType(vntName) = vbString Then strName = Trim(vntName)
        If VarType(vntEmail) = vbString Then strEmail = Trim(vntEmail)
        'アドレスのみか
        If strName = "" Then
            JointMailAddress = strEmail
        Else
            JointMailAddress = strName & " <" & strEmail & ">"
        End If
    End If
End Function
  1. 以下の2つの参照設定を有効化します。
    Microsoft CDO for Windows 2000 Library
    Microsoft Scripting Runtime
  1. あとは任意のプロシージャでクラスを叩くだけです。
    SMTPサーバなどパラメータで指定しなければクラスで定義した標準値が使用されます。
With New SendMailCDO
    .prpFromName = ""                                           '差出人(String)
    .prpFromAddr = ""                                           '差出人アドレス(String)
    .prpToName = Range("$I$3:$I$100")                           '宛先名(Range)
    .prpToAddr = Range("$J$3:$J$100")                           '宛先アドレス(Range)
    .prpCCName = Range("$K$3:$K$100")                           'CC名(Range)
    .prpCCAddr = Range("$L$3:$L$100")                           'CCアドレス(Range)
    .prpBCCName = Range("$M$3:$M$100")                          'BCC名(Range)
    .prpBCCAddr = Range("$N$3:$N$100")                          'BCCアドレス(Range)
    .prpOwnerBCC = Cells(30, 2).Value = "送信者をBCCに加える"   '差出人BCC指定(String)
    .prpAttachFile = Range("$B$25:$H$29")                       '添付ファイル名(Range)
    .prpSubj = Cells(8, 2).Value                                '件名(String)
    .prpBody = Cells(9, 2).Value                                '本文(String)
    .prpSign = Cells(20, 2).Value                               '署名(String)
    .prpSMTP = ""                                               'SMTPサーバアドレス(String)
    .prpPort = 587                                              'ポート№(Integer)
    .prpAuthenticate = 1                                        '認証指定(Integer) 0=無し、1=有り
    .prpUseSSL = False                                          'SSL使用(Boolean)
    .prpSendUserName = "S00000000"                              '認証ユーザーID(String)
    .prpSendPassword = "pass"                                   '認証パスワード(String)
    If .SendMail = False Then
        MsgBox .prpErrMSG, vbCritical
    End If
End With