Mutable_Yunの業務改善ブログ

業務改善や生産性向上のブログです。自動化の手段として、VBAやRPAの勉強に役立つ解説をしています。

VBA クラスモジュールの使い方を超簡単に日本語のクラス名で具体的に解説する③ メールを作成するのに必要な機能を備えたクラスを作る

前回まででクラスモジュールの意義、目的、クラスとは何か、オブジェクトとは何かが分かりました。サンプルコードがシンプルすぎて実用的では無かったので、今回はメールの配信先を取得するという実用的なクラスを作っていきます。

実際に使えるクラスを作ってみることで、クラスの概念がはっきりと分かってきます。この記事のサンプルコードはコピペ禁止です(笑)自分の手で打ち込んでいきましょう。(写経と言います)

この記事は初段です。
レベルについてはExcel VBAの実力(レベル)を定義してみる 初心者~三段をご参照ください。

注意:メールを作成する事自体がAPIという技術を使う事であり、クラスの概念が必要です。この記事はメールの作成方法自体は解説しません。エクセルVBAでメールを作成する方法が分からない方は、先にVBA APIを使ってメールを配信するをご覧下さい。

目次

今回やりたいことの概要

今回やりたいことはOutlookのメールの作成に必要な情報を用意する事です。メール作成を行うためには宛先の所にメールアドレスを入れたり、件名を入力したり、本文を入力したり、添付ファイルをつけたり、いろいろと作業が必要です。

でも、やりたいことは大体毎回同じ。そこで、メール作成に必要な様々な情報を取得する機能(=プロシジャ)を持ったクラスを生成します。

方針としては、Functionプロシジャの復習も兼ねて、ある程度まとまったコードである宛先の作成を、まず普通のFunctionプロシジャとして作成します。

その後、は楽勝で作れる件名と本文の作成、添付ファイルをつける部分はいきなりクラスに作っていきます。

名簿からメールの配信先を作成する

シートに一覧表を作っておく

先日、VBAを教えている人のコードを見てびっくりしました。関連部門にデータを一斉配信するVBAのプログラムなのですが、なんと、宛先が標準モジュールのSubプロシジャの中にベタ打ち!どこからのブログからコピペして、宛先などの所を修正して作ったそうです。このようなことにならないよう、宛先は一覧表を作っておきましょう。

メールの配信先を一覧表にしておく
メールの配信先を一覧表にしておく

この一覧表の3列目に「to」または「cc」が入力されています。これは、toの行の人はメールのAttentionにccの行の人はCCの宛先に入れることを意味しています。

まずは普通のFunctionプロシジャを作ってみる

メールの宛先を設定するとはどういうことでしょうか?それはメールアドレスを「; 」(セミコロンと半角スペース)で区切ってつないだ文字列を作ると言うことです。この記事は初段レベルなので、Functionプロシジャの解説は省いていきなりサンプルコードを示します。

Function メールの宛先を作成する() As Variant

    Dim メールの宛先_arr(2) As Variant  'インデックス0にAttention、1にCCの宛先の文字列を格納する、2はBCC
    Dim i As Long ’カウンタ変数はi。これを日本語にしたら逆に分かりづらい
    Dim 最終行_long As Long
    Const メアドの列_long As Long = 2, 宛先区分の列_long As Long = 3
    
    最終行_long = Cells(Rows.Count, 1).End(xlUp).Row
    
    For i = 1 To 最終行_long
        Select Case Cells(i, 宛先区分の列_long)
            Case "to"
                メールの宛先_arr(0) = メールの宛先_arr(0) & Cells(i, メアドの列_long) & "; "
            Case "cc"
                メールの宛先_arr(1) = メールの宛先_arr(1) & Cells(i, メアドの列_long) & "; "
            Case Else
                メールの宛先_arr(2) = メールの宛先_arr(2) & Cells(i, メアドの列_long) & "; "
        End Select
    Next i
    
    メールの宛先を作成する = メールの宛先_arr
    
End Function

Functionプロシジャの戻り値をVariantで宣言して、配列を代入することで、Attention、CC、BCCに入れる3つのメールアドレスの文字列を一度に返しています。

クラスモジュールを作る

クラスモジュールを作ります。分かりやすいクラス名をつけます。今回はクラス名を「メールに必要な情報作りクラス」にします。わかりやすっ!このクラス名が、標準モジュールで生成するインスタンスの型になるんでしたね。それではクラスを作ります。

クラスモジュールを作成。クラス名はオブジェクトの型になるので超分かりやすくつける
クラスモジュールを作成。クラス名はオブジェクトの型になるので超分かりやすくつける

さっき作った宛先を作るFunctionプロシジャをクラスのメソッドにする

オブジェクトは「データ」と「機能」を持ったモノ。そのオブジェクトを設計するのがクラスモジュールでしたね。どんなデータを持っているのか、どんな機能を持っているのか。今回は予め持っているデータは無くて、データはシートにある宛先一覧です。

それでは機能を作成していきます。

宛先を生成するメソッドを作る

メソッドは機能です。クラスモジュールの中ではSubプロシジャやFunctionプロシジャで書くんでしたよね。さっき、とりあえず標準モジュール内で作ったFunctionプロシジャを切り取って(Ctrlとx同時押し)クラスモジュールに貼り付けます(Ctrlとv同時押し)。

いま、クラスモジュールにFunctionプロシジャが書かれた状態になっています。VBA クラスモジュールを解説する② Propertyプロシジャを作るで解説したように、実際に使う時はプロパティの値として取り扱います。

Interior.ColorIndex = 3

を思い出しましょう。3に当たる部分が、今回のメールアドレスの宛先の部分です。メールアドレスの宛先の部分を求める為のFunctionプロシジャをまず作りました。Interior.ColorIndex = 3の例で言えば3を求める作業。

クラスのプロパティはProperty GetとProperty Letで取り扱うんでしたよね。今回は、標準モジュールから見て、メールの宛先になる文字列の値を取得して、その値を使いたいのでProperty Getで標準モジュールから見て取得します。(ほへ?ってなってる方は前回の解説、もう一回読んで下さいね)

'このコードは「メールに必要な情報生成クラス」というクラスモジュール内に書く
'Function メールの宛先を作成する() As Variant ←これを消して、
Property Get メールの宛先を作成する()  '←Property Getに書き換えた

    Dim メールの宛先_arr(2) As Variant  'インデックス0にAttention、1にCCの宛先の文字列を格納する、2はBCC
    Dim i As Long
    Dim 最終行_long As Long
    Const メアドの列_long As Long = 2, 宛先区分の列_long As Long = 3
    
    最終行_long = Cells(Rows.Count, 1).End(xlUp).Row
    
    For i = 1 To 最終行_long
        Select Case Cells(i, 宛先区分の列_long)
            Case "to"
                メールの宛先_arr(0) = メールの宛先_arr(0) & Cells(i, メアドの列_long) & "; "
            Case "cc"
                メールの宛先_arr(1) = メールの宛先_arr(1) & Cells(i, メアドの列_long) & "; "
            Case Else
                メールの宛先_arr(2) = メールの宛先_arr(2) & Cells(i, メアドの列_long) & "; "
        End Select
    Next i
    
    メールの宛先を作成する = メールの宛先_arr
    
End Property

ここまでくれば、あとは標準モジュールでRange("A1").Interior.ColorIndex=3と同じ感覚で使えます。

ちょっとここら辺でテストしておきます。標準モジュールでインスタンスの生成と表示をすればいいんですよね。初段向けの記事なので、MsgBoxではなくDebug.Printで行きます。

いい感じです。このままメールの宛先に代入できる形になりました。

試しに実行してみた結果。イミディエイトウィンドウで表示
試しに実行してみた結果。イミディエイトウィンドウで表示

件名以降は説明省略

一番難しい宛先の取得を題材にしました。Property Getの使い方のイメージが掴めてきたと思います。件名とか本文は定型文ベタ打ちですよね。Property Getプロシジャの中で固定分を打ち込んでしまいましょう。何なら、標準モジュールでグローバル変数を宣言してそこに代入してもOKです。代入する場所はもちろん標準プロシジャですよ!クラス内で定義してもできますが、それだと、何のためのクラスなんだ。。。って事になります。(⇒メンテナンス性ですね)

まとめ

  • 標準モジュールでいままでFunctionプロシジャで値を求めていた手順はクラスモジュールにできる
  • そもそもクラスモジュールは似たようなFunctionやSubプロシジャをまとめる役割がある
  • Range("A1").Interior.ColorIndex = 3 の3を求める為のオブジェクトを作った(⇒コピペじゃ無くて写経した人のみ)

ここまでを自由自在にできれば、VBAのオブジェクト指向はほぼマスターできたと言えます。新しい言葉を伝授します。隠蔽化(カプセル化とも言います)です。機能をひとまとめにしたクラスは標準モジュールからみても分からないですよね。隠蔽化して標準モジュールだけでは何をやっているか分からなくなっているのに、メンテナンス性はあがっている。これが、クラスです。

もうVBA二段が見えています。

<余談>

皆さんは初段で、二段に向けて勉強中だと思います。実は他言語(例えばJava)では、このクラスとオブジェクトの概念が分かって初級者(初心者ではない)扱いです。

つまり、他言語(例えばJava)の初級者のレベルがVBAで言う、初段くらいなんです。ここはがっかりするところではありません。逆にクラスが分からなくてもかなりの自動化ができるがVBAの強みです。オブジェクト指向は一つの山場です。他言語でプログラミング学習に挫折しやすい原因の一つがここにあります。オブジェクト指向が分からないから初級者で終わってしまう。

そのVBAの強みが裏目にでるのが「クラスモジュールは分かっていなくてもいい」という誤解です。この山場を超えると逆にクラスを使わない方が不便に思えてくるくらい便利な概念です。

VBAでオブジェクト指向。頑張っていきましょう!(ちなみにこの記事完全に理解した人はJavascript(Javaじゃないですよ)は3日で相当できる様になります。)