メール自動作成用のクラスを作る~(2)
先に断っときます。今回はカンバンに偽りあり。
「……クラスを作る」とか題名で言ってますが、クラスは作りません。ただ、前回作ったクラスを活用するためのコードを作るんだから、あながち嘘でもない。そんなわけで、そこんとこヨロシク。
前回作ったクラス「MailData」では、メール作成に必要なデータを4つに分けて取得するようにしていた。すなわち、
- メールの基礎データ
- メール本文の配列
- 添付ファイルのフルパスの配列
- 送信者データの配列
の4つだ。
……てことは、まずはこれらのデータをワークシートから取得する処理を書かねばならん、ということだ。
諸データ取得メソッドを作る
基礎データ取得メソッド
基礎データを、構造体の形でまとめる処理を書く。このメソッドは、他には使い道がないと思うので、Privateで呼び出され専用にする。他の3つも同じ。
Private Sub setMailBasicData(ByRef baseCell_ As Range)
Dim baseRow_ As Integer
baseRow_ = baseCell_.Row '……(1)
With baseCell_.Parent '……(2)
'送信相手の基本情報を構造体の各要素にセット
mldt.mailTo = .Cells(baseRow_, colNum.mailTo).Value '……(3)
mldt.CC = .Cells(baseRow_, colNum.CC).Value
mldt.BCC = .Cells(baseRow_, colNum.BCC).Value
mldt.mailSubject = .Cells(baseRow_, colNum.mailSubj).Value
mldt.belongsTo = .Cells(baseRow_, colNum.belongsTo).Value
mldt.jobTitle = .Cells(baseRow_, colNum.jobTitle).Value
mldt.personName = .Cells(baseRow_, colNum.personName).Value
mldt.returnReceipt = .Cells(baseRow_, colNum.returnReceipt).Value
End With
End Sub
今回のマクロは、メール作成用のデータが「1件につき1行」という形になっていて、「対象データの行のB列を選択した状態でマクロを実行する」というやり方にしている。従って、データを拾い出すときの基準として選択中のセルを渡すことになる。引数の「baseCell_」というのはそういうことです。
さて、コードの解説。
- ワークシートで選択中のセルの行が、各種データを集める際の基準になるので、(1)で引数として渡されたセルの行番号を変数「baseRow_」に格納している。
- (2)で、引数として渡されたセルのParentプロパティを取得している。要するにメール作成用データが入力されたシート(「Main」ワークシート)のこと。以下、「End With」まで、「Main」ワークシートに対する操作。
- (3)からの8行で、構造体「mldt」の各要素にデータを持たせている。
「Main」ワークシートの列の指定には列挙体を使っているので、何の列を指しているのか分かりやすいと思う。
メール本文の配列取得メソッド
Private Sub setMailBody(ByRef baseCell_ As Range, _
ByVal n As Integer)
'※引数「n」は、本文が入力されているセルの数
Dim baseRow_ As Integer
baseRow_ = baseCell_.Row
ReDim mlBody(n) '……(1)
Dim i As Integer
With baseCell_.Parent
For i = 1 To n
mlBody(i) = .Cells(baseRow_, colNum.p01 + i - 1).Value '……(2)
Next
End With
End Sub
このメソッドには、引数として基準セルと本文データの入っているセルの数を渡す。
- 配列の要素数「n」でmlBody()をReDimする。
- あとは、Forループを使ってmlBody()の各要素にデータを放り込んでいるだけ。Cellsプロパティの列インデックスが、カウンタ変数「i」がインクリメントするごとに「0,1,2,……」とインクリメントするので、右へ右へと値を取得して配列にセットしていく感じになる。
添付ファイルフルパスの配列取得メソッド
メール本文の取得とほぼ同じやり方なので、コードを載せるだけにする。
Private Sub setAttachmentFiles(ByRef baseCell_ As Range, _
ByVal n As Integer)
'※引数「n」は、添付ファイルのフルパスが入力されているセルの数
Dim baseRow_ As Integer
baseRow_ = baseCell_.Row
ReDim mlAttFiles(n)
Dim i As Integer
With baseCell_.Parent
For i = 1 To n
mlAttFiles(i) = .Cells(baseRow_, colNum.att01 + i - 1).Value
Next
End With
End Sub
送信者データの取得メソッド
送信者のデータは、別シートで管理しているので、
あらかじめこんな風にデータ範囲に名前を付けておく。今回は「UserInformationTable」としている。
そうしたら、
Range("UserInformationTable").Rows.Count
これで送信者データが何種類あるか取得できるので。
Private Sub setSenderData(ByVal n As Integer)
'※引数「n」は、送信者データの数
ReDim mlSenderData(n)
Dim i As Integer
For i = 1 To n
mlSenderData(i) = ThisWorkbook.Worksheets("ユーザ情報").Cells(i, 2).Value
Next
End Sub
これはもう説明不要だと思う。
メインメソッドを作る
上記4つのメソッドをそれぞれ呼び出してやれば、「MailData」クラスのインスタンスにデータを渡す準備は完了、ということになる。
メインメソッドのコード
Sub voidMain()
Dim baseCell As Range
Set baseCell = ActiveCell
If booleanCheckActiveCell(baseCell) = False Then '……(*)
Call makeUserSick '……(**)
Set baseCell = Nothing
Exit Sub
End If
Dim objSh As Worksheet
Set objSh = baseCell.Parent
Dim n As Integer 'カウント用変数
Dim baseRow As Long
baseRow = baseCell.Row
'構造体変数mldtに、メールの基本情報をセットする
Call setMailBasicData(baseCell) '……(1)
Set md = New MailData '……(2)
'MailBodyクラスのインスタンスにメールの基礎データをセット
md.getMailBasicData mldt '……(3)
With md
Debug.Print "★★★メール基礎データ★★★" '……(4)
Debug.Print .mailTo
Debug.Print .CC
Debug.Print .BCC
Debug.Print .mailSubject
Debug.Print .belongsTo
Debug.Print .jobTitle
Debug.Print .personName
Debug.Print .returnReceipt
End With
'本文文字列の入っているセルを数えて変数「n」にセット
Dim i As Integer
n = 0 '……(5)
For i = colNum.p01 To colNum.p10 '……(6)
If objSh.Cells(baseRow, i).Value = "" Then '……(7)
Exit For '……(8)
Else
n = n + 1 '……(9)
End If
Next
'本文を配列に格納する。
Call setMailBody(baseCell, n) '……(10)
'MailDataクラスのインスタンスにメール本文の配列をセット
md.getMailBodyArray mlBody() '……(11)
Debug.Print "★★★本文の配列★★★" '……(12)
For i = 1 To UBound(mlBody())
Debug.Print md.mailBody(i)
Next
'添付ファイルのフルパスが入っているセルを数えて変数「n」にセット
n = 0 '……(13)
For i = colNum.att01 To colNum.att10
If objSh.Cells(baseRow, i).Value = "" Then
Exit For
Else
n = n + 1
End If
Next
'添付ファイルのフルパスを配列に格納する。
Call setAttachmentFiles(baseCell, n)
'MailDataクラスのインスタンスに添付ファイルフルパスの配列をセット
md.getMailAttFilesArray mlAttFiles()
Debug.Print "★★★添付ファイルフルパス★★★"
For i = 1 To UBound(mlAttFiles())
Debug.Print md.attFiles(i)
Next
'送信者データを配列に格納する '……(14)
Call setSenderData(Range("UserInformationTable").Rows.Count)
'MailDataクラスのインスタンスにユーザー情報の配列をセット
md.getSenderDataArray mlSenderData()
Debug.Print "★★★送信者データ★★★"
For i = 1 To UBound(mlSenderData())
Debug.Print md.senderData(i)
Next
End Sub
Private Function booleanCheckActiveCell(ByRef nowSelecting As Range) As Boolean '……(*)
With nowSelecting
If nowSelecting.Parent.Name <> MAIN_SHEET_NAME Then
MsgBox "この痴れ狗めぐぁーーーーーーッ!", vbCritical
MsgBox "そもそも「" & MAIN_SHEET_NAME & "」ワークシートを選ぶところから出直してこいや!"
Exit Function
End If
'アクティブセルの位置がおかしいときは終了。
'番号のセルを選んでいないときは、メッセージを表示して終了
If .Column <> colNum.numOf Then
MsgBox "番号のセル(B列)を選んで出直してこいや!", vbCritical
Exit Function
End If
'1行目を選んでいるときは、メッセージを表示して終了
If .Row = 1 Then
MsgBox "ぼけーーーーーー!", vbCritical
MsgBox "そこを選んでどうするねん!", vbExclamation
Exit Function
End If
'送信済みフラグがあるときは、メッセージを表示して終了
If .Cells(nowSelecting.Row, colNum.isSent).Value = "済" Then
MsgBox "二重に送ってどうするねん!", vbCritical
Exit Function
End If
'宛先がないときは、メッセージを表示して終了
If .Parent.Cells(nowSelecting.Row, colNum.mailTo).Value = "" Then
MsgBox "(゚Д゚)ハァ?", vbCritical
MsgBox "宛先アドレスが空欄なんやけど?", vbExclamation
Exit Function
End If
End If
End With
booleanCheckActiveCell = True
End Function
Private Sub makeUserSick() '……(**)
MsgBox " _________" & vbCrLf & _
" / \ " & vbCrLf & _
"/ /・\ /・\ \" & vbCrLf & _
"|  ̄ ̄  ̄ | ち~んw" & vbCrLf & _
"| (_人_) |" & vbCrLf & _
"| \ | |" & vbCrLf & _
"\ \_| /"
End Sub
コードの解説。
- (*)のところは、起動時のチェック。マクロ実行時に「Main」ワークシートのB列を選択しているかどうかとか、そういう最低限のチェックをしている。下の方の(*)を付けたメソッドでチェックしている。
- チェックを通らなかったら、(**)でユーザを煽る仕様w
- (1)。選択中のセルを引数として渡してsetMailBasicDataメソッドを実行。これで、構造体変数「mldt」の各要素にデータがセットされる。
- (2)でMailDataクラスのインスタンスを生成。
- (3)でMailDataクラスのgetMailBasicDataメソッドに引数「mldt」を渡してプロパティに各データをセット。
- (4)から8行は、各データがちゃんとセットされているかどうかを確認するためのDebug.Print。
- 今度は本文データの取得とセット。(5)でカウント用変数「n」を初期化。
- (6)から7行のForループで、本文用の10個のセルのうち、文字列が入っているセルを数える。
列挙体で開始列番号と終了列番号を指定しているので、読みやすいと思う。 - (7)で空白セルかどうかを判定。空白なら(8)でループを抜ける。空白でなかったらカウント変数「n」をインクリメントする。
- Forループが終わると、「n」には本文の入ったセルの数、すなわち配列の要素数が入っていることになるので、(10)でsetMailBodyメソッドを引数として基準セルと配列の要素数「n」を渡して実行する。
- (10)の実行後は、配列「mlBody()」に本文データが格納されているので、(11)で、配列「mlBody」を引数として渡してMailDataクラスのgetMailBodyArrayメソッドを実行する。
- (12)は、メール本文のデータがちゃんとMailDataクラスのプロパティにセットされているかどうかをチェックするためのDebug.Print。
- (13)以降は、添付ファイルフルパスのセットと確認用のDebug.Print。本文データとほとんど同じ処理なので説明は省略。
- (14)以降は、送信者データのセットと確認用のDebug.Print。これも説明は省略。
とりあえず、ここまで。もし、(13)とか(14)のところの意味が分からなかったら、(5)~(12)までをよーく解読してみてほしい。まあ、あまりうまく説明できているとも思えないので、質問とか寄せてくださったらありがたい。
実行
「Main」ワークシートのB列を選択して実行すると……、
ほれ、この通り、イミディエイト・ウインドウに、無事全てのデータが表示されている。
これで、このワークブックから、必要な全てのデータが取得できた。あとは、LotusNotesとかThunderbirdとか、メーラーに合わせてメールを作成するメソッドを書けば良い。たぶん、OutLookにも対応できるだろう。
ちなみに、選択すべきセルを選択せずに実行すると、
こんな具合に煽られますwww
※「痴れ狗めぐぁーーーーーーッ!」ってのは、マンガ『蒼天航路』の董卓のセリフが元ネタです。
ひとりごと
それぞれのメーラーに合わせたメール作成用メソッドなんだけど、メーラーごとに別々のクラスを作って、同じメソッド名(たとえば「createMail」とか)にした方がいいんだろうか?
VBAでもInterfaceが使えるらしいんだけど、Interface型の変数が使えるんだったら、ポリモーフィズムができるということなんだろうか? まあ、今のやり方だと「ポリモーフィズムが使えたとして何がうれしいんだよ!?」ということなんですけど……。
まだまだ勉強が必要ですね。そこら辺、詳しい人がいたらヒントをくれください。