Unityでメールを送りたい
色々ときっかけはあるのですが、省略してやりたいことを言います。
Slackをいろいろとプログラムで弄りたいときに、大抵は皆さんBOTを準備されると思うのですが、BOTを入れる権限がないSlackチャンネルでもいちおうできることがあります。それが、Slackのメール転送機能です。
Slackのチャンネル全体の設定から 環境設定 >> メッセージ&メディア >> Slack へのメールの転送 と進むと、件の機能にたどり着くことができます。
どんな重要メールも、固有のユニークメールアドレスに転送することで Slack にアップロードすることができます。メールは Slackbot がお届けし、非公開のままにしておくことも、またはチームと共有することもできます。
と、短く説明書きがあり、設定をすることで「固有のユニークメールアドレス」を発行することができます。
要するに、こいつにメール送るとSlackでも通知来るよって機能なのですが、こいつにUnityからメール送ってSlackに転送させたかった。
それがやりたいことの概要になります。
...なぜUnityかとか、聞かないでください。
プログラマーたるもの、自分のフィールドで戦いたいこともあるんじゃないですかね...笑
既存のUnityメール送信実装案の検討
UniMail
まあ、有名なやつで、UniMailってやつがあります。
UniMailの内部の処理は以外と簡単で、
Application.OpenURL(string.Format("mailto:{0}?subject={1}&body={2}", mailTo, Uri.EscapeDataString(subject), Uri.EscapeDataString(body)));
この一文に尽きるって感じかなぁ。エディタでやるとなると特に。
自分の読解力がなくて見落としているかもですが。
結論を言うと、これ、自分の環境ではURLが開くだけでメール送信はできませんでした。
Gmailで送信(コガネブログ様)
こちらの記事も調べている中で出てきました。
これは普通にいけそう。
でも当時の自分は、何をトチ狂っていたのか、勉強したてのUnityWebRequestを使いたいと思ってまして、これを却下してしまいました。
そこにこだわったせいで、慣れない別言語で苦しむことになるのですが...。
GASを使うのだ
GAS(GoogleAppsScript)には便利なAPIがあることを、少し前から自分は知っていました。
GmailApp.sendEmail('メールアドレス', '件名', '本文');
そうだ、これを使えばUnityでもメール送信できるじゃん!とか思って、そこから苦難の道が始まるんすよね...orz
- いちおうスプレッドシートにログを残して、とか考えたせいで、スプレッドシートからGASにたどり着くまでに苦労するし...
(以前使っていたときはメニューバーのツールからいけたんですけど、いつのまにか拡張機能に移動していた) - Chromeでログインしているアカウントとは違うGoogleアカウントのスプレでやろうとしたから、そもそもGAS開けられないし...
(GASはChromeでログインしているアカウントと同じアカウントじゃないとGASにたどり着けないらしい) - GASは変更があったら毎度毎度「新しいデプロイ」にしなきゃいけないことに詰まるし...
という、環境面で散々でした。
もちろん言語面でも苦労はあったんだけど、なんとか切り抜けました...。
実際の実装
GAS(GoogleAppsScript)側の実装
function doPost(e)
{
// パラメータでJsonを受け取り、パース
const jsonString = e.postData.getDataAsString(); //文字列で取得
const date = JSON.parse(jsonString); //Object形式に変換
const toMail = date.toMail; //メアド
const subject = date.subject; //件名
const body = date.body; //本文
const timerecord = Utilities.formatDate(new Date(), "Asia/Tokyo", "yyyy/MM/dd HH:mm:ss"); //時刻
const writeDate = [[timerecord, date.toMail, date.subject, date.body]];
//スプレッドシートにログを残す
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getActiveSheet();
const maxRow = sheet.getMaxRows();
const lastRow = sheet.getRange(maxRow, 1).getNextDataCell(SpreadsheetApp.Direction.UP).getRow();
sheet.getRange(lastRow+1, 1, 1, 4).setValues(writeDate);
//メール送信
GmailApp.sendEmail(toMail, date.subject, date.body);
let output = ContentService.createTextOutput();
output.setMimeType(ContentService.MimeType.JSON);
output.setContent(JSON.stringify({ message: "success" }));
return output;
}
Unity側の実装
実際はUniTask使っていたんですけど、こちらではコルーチン版貼りますね。
いちおう挙動は確認済です。
using System;
using System.Collections;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
public class SlackMail : MonoBehaviour
{
// 必要なデータ
[SerializeField] private MailData mailData = null;
// GASの公開リンク
[SerializeField] private string URI = "";
private static readonly (string name, string value) header = ("Content-Type", "application/json");
[System.Serializable]
public sealed class MailData
{
public string toMail; //メールアドレス
public string subject; //件名
public string body; //本文
}
[System.Serializable]
public sealed class ResponseData
{
public string message;
}
private void Start()
{
StartCoroutine(Post(mailData));
}
private IEnumerator Post(MailData postMailData)
{
if (mailData == null)
{
yield break;
}
var json = JsonUtility.ToJson(postMailData);
var bodyRaw = Encoding.UTF8.GetBytes(json);
var request = new UnityWebRequest(URI, UnityWebRequest.kHttpVerbPOST)
{
uploadHandler = new UploadHandlerRaw(bodyRaw),
downloadHandler = new DownloadHandlerBuffer()
};
request.SetRequestHeader(header.name, header.value);
yield return request.SendWebRequest();
// 非同期処理の結果を参照する
if (request.result != UnityWebRequest.Result.Success)
{
// 通信失敗時
Debug.LogException(new Exception(request.error));
yield break;
}
var result = request.downloadHandler.text;
Debug.Log(result);
var response = JsonUtility.FromJson<ResponseData>(result);
Debug.Log(response.message);
}
}
あとは、必要事項をUnityエディタから登録してもらって...
あとがき
なんだかんだ言って、GASがわかってきた気がするので、これ使って色々しようかなと。
UnityのNetcodeと連携とか、純粋にGASのみで開発もありっすね。
まあ、疲れましたが...
参考文献
これは書籍だけど、貼っておくか...参考になったので...