fc2ブログ

記事一覧

メールを送信する方法 | Xamarin.Forms


今回は Xamarin でメーラーを利用してメールを送信する方法についてご紹介いたします。バックグラウンドで直接送信する場合は MailKit 等でも送信ができますが、この記事ではフロントエンドでユーザーが内容を修正できるように他のメーラーアプリを画面表示して送信する方法を試してみました。
iOS と Android で同じ呼び出しコードにするため、毎度お馴染みDependencyService での記述になりますが、Android では少し気を付ける点があります。

Android5
xamarin_mail_01.jpg
Android4
xamarin_mail_02.jpg



前提条件
・Windows10
・Visual Studio 2015 Community Update3
・Xamarin 4.3.0.784 (NuGet Xamarin.Forms 2.3.4.224)
・macOS Sierra 10.12.4 / Xcode8.3.1 / Xamarin.iOS 10.4.0.123



1.PCLの記述方法

PCLプロジェクト内に DependencyService で呼び出すためのインターフェースを配置します。
IMailService.cs
namespace AppName.Services
{
public interface IMailService
{
    bool StartMailer(string title, string body, string[] to, string[] cc, string[] bcc, string filePath, ref string err);
}
}



2.Androidの実装方法

Android プロジェクト内に MailService クラスを配置します。
注意点が3つあります。
(1)intent.SetType("message/rfc822"); の記述を先頭で記述すると動作しませんでした。
(2)intent.SetData(Android.Net.Uri.Parse("mailto:" + to)); の記述をするほうが対応メーラーが広がるそうです。
(3)添付ファイルを付ける場合は、Android.Net.Uri.FromFile で添付することがより多くのメーラーとの相性が良くなるらしいです。
Android7 以降はFileProviderを使用してファイルパスを Content:// で渡すことが必須となりました。

MailService.cs
using System;
using Android.Content;
using Xamarin.Forms;
using AppName.Services;
using AppName.Droid.Services;
[assembly: Dependency(typeof(MailService))]
namespace AppName.Droid.Services
{
public class MailService : IMailService
{
    public bool StartMailer(string title, string body, string[] to, string[] cc, string[] bcc, string filePath, ref string err)
    {
        try
        {
            //初期化
            err = String.Empty;

            var intent = new Intent();

            //アクションにACTION_SENDを指定して暗黙的インテントを呼び出すことで、
            //インストールされているアプリで対応可能なものが列挙されます。
            intent.SetAction(Intent.ActionSend);
            intent.AddFlags(ActivityFlags.NewTask);

            //項目セット
            intent.SetData(Android.Net.Uri.Parse("mailto:" + to));
            if (to != null && to.Length > 0)
            {
                intent.PutExtra(Intent.ExtraEmail, to);
            }
            if (cc != null && cc.Length > 0)
            {
                intent.PutExtra(Intent.ExtraCc, cc);
            }
            if (bcc != null && bcc.Length > 0)
            {
                intent.PutExtra(Intent.ExtraBcc, bcc);
            }
            intent.PutExtra(Intent.ExtraSubject, title);
            intent.PutExtra(Intent.ExtraText, body);

            if (String.IsNullOrEmpty(filePath))
            {
                //ファイル添付なし
                //intent.SetType("text/plain");
                intent.SetType("message/rfc822");
            }
            else
            {
                //ファイル添付あり
                intent.SetType("message/rfc822");
               
//Androidバージョンにおけるファイルパスの対応
Java.IO.File sendFile = new Java.IO.File(filePath);
Android.Net.Uri uri = null;
if ((int)Build.VERSION.SdkInt < (int)(BuildVersionCodes.N))
{
//Android6.0以前
uri = Android.Net.Uri.FromFile(sendFile);
}
else
{
//Android7.0以降
uri = Android.Support.V4.Content.FileProvider.GetUriForFile(
Forms.Context,
Forms.Context.PackageName + ".fileprovider",
sendFile
);
}
            }

            //メーラー起動
            Forms.Context.StartActivity(intent);

        }
        catch (Exception ex)
        {
            err = ex.Message;
            Console.WriteLine(ex.Message + System.Environment.NewLine + ex.StackTrace);
            return false;
        }
        return true;
    }
}
}



3.iOSの実装方法

iOS プロジェクト内に MailService クラスを配置します。
MailService.cs
using Foundation;
using UIKit;
using MessageUI;
using Xamarin.Forms;
using AppName.iOS.Services;
using AppName.Services;
[assembly: Dependency(typeof(MailService))]
namespace AppName.iOS.Services
{
public class MailService : IMailService
{
public bool StartMailer(string title, string body, string[] to, string[] cc, string[] bcc, string filePath, ref string err)
{
//初期化
err = String.Empty;
string ret = String.Empty;

if (!MFMailComposeViewController.CanSendMail)
{//メール送信が可能かどうかの確認
err = "この端末はメールが送信可能な状態にありません。";
return false ; //メール送信不能
}

var mail = new MFMailComposeViewController();//インスタンスの生成

//項目セット
if (to != null && to.Length > 0)
{
mail.SetToRecipients(to);
}
if (cc != null && cc.Length > 0)
{
mail.SetCcRecipients(cc);
}
if (bcc != null && bcc.Length > 0)
{
mail.SetBccRecipients(bcc);
}
mail.SetSubject(title);
mail.SetMessageBody(body, false);

if (!String.IsNullOrEmpty(filePath))
{
//ファイル添付あり

//拡張子
string extention = System.IO.Path.GetExtension(filePath.ToLower()).Replace(".", "");
if (String.IsNullOrEmpty(extention))
{
//拡張子が取得できない場合はテキストで開く
extention = "txt";
}
//mime type
string mimetype = MimeTypeUtility.GetMimeType(extention);

NSData data = NSData.FromFile(filePath);
mail.AddAttachmentData(data, mimetype, System.IO.Path.GetFileName(filePath));
}

mail.Finished += (o, args) => {
//送信処理終了時のイベント
ret = args.Result.ToString(); // srgs.Result:戻り値
args.Controller.DismissViewController(true, null); //Eメール画面の消去
};

//メーラー起動
var view = UIApplication.SharedApplication.KeyWindow.RootViewController;
view.PresentViewController(mail, true, null);
err = ret;
return true;
}
}
}

※拡張子から MimeType を取得する方法(MimeTypeUtility.GetMimeType)につきましては以下の URL にてご紹介しております。
https://itblog.dynaspo.com/blog-entry-175.html



4.使用方法

PCL プロジェクトの中の任意のページに記述します。
Test.xaml.cs
using AppName.Services;
using Xamarin.Forms;
public partial class TestPage : ContentPage
{
async void OnSendMailButtonPress()
{
    string errMsg = String.Empty;
    DependencyService.Get<IMailService>().StartMailer("タイトル", "本文", null, null, null, this.txtFilePath, ref errMsg);
    if (String.IsNullOrEmpty(errMsg))
    {
        await this.DisplayAlert("メール送信完了",
                                "メール送信完了しました。" + System.Environment.NewLine +
                                errMsg, "OK");
    }
    else
    {
        await this.DisplayAlert("メール送信失敗",
                                "メールが送信できませんでした。" + System.Environment.NewLine +
                                errMsg, "OK");
    }
}
}

SMS を送信したい場合は、次の記事「Xamarin.FormsでSMSを送信する方法」をご参考ください。

※2017/10/26追記
説明文を追加しました。



最後までお読みいただきありがとうございます。
当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
https://itblog.dynaspo.com/blog-entry-81.html


関連記事

コメント

Re: たびたびごめんなさい。
naoさんへ

以下、インラインで回答させていただきます。

> 1:AppNameというのはソリューション名になりますか?
→はい。さようでございます。
 AppNameのみ置換してご利用ください。

> 2:PCLにServicesというフォルダを設けてIMailServiceインターフェースを作られていますか?
→はい。わかりやすいように全てのプロジェクトで同一の「Services」というフォルダ内に格納しております。

> 3:そのあとにAndroidに同様にServicesフォルダを作ってその配下にMailService.csクラスを作られていますか?
> namespaceからそのように判断してしまっていました。
→はい。最初にご質問を頂きました後に、判断ができやすいようにnamespaceを追加しました。

> 4:MailService.csのtypeof(MailService)で「MailServiceは名前空間ですが種類のように使われています。」と言われてしまい、SendMailPage.xaml.csで「this.txtFilePathの個所でそのようなものはありません。」と出てしまいました。
→具体的なソースを見ていないので何とも言えませんが、
 名前空間に関する記述ミスがあるはずです。
 同じ名称の名前空間またはクラスが存在しませんか?
 「MailService」と同じ名称が名前空間にありませんか?
 (ex using AppName.Droid.Services.MailService; ×)
 「MailService」というクラスが重複していませんか?
 または、最近のXamarinで作成したプロジェクトは、Androidプロジェクトの名前空間が AppName.Androidとなっており、global::Androidと紛らわしくなっています。
 using Droid = AppName.Android; として重複を避ける、または、プロジェクト名を AppName.Droidに変更する等対策が必要です。 
 ちなみにtypeof(MailService)はiOSとAndroidのどちらのプロジェクトでしょうか?
たびたびごめんなさい。
基本的なことになってしまうかもしれないのですが、もしよければ質問させてください。

1:AppNameというのはソリューション名になりますか?

2:PCLにServicesというフォルダを設けてIMailServiceインターフェースを作られていますか?

3:そのあとにAndroidに同様にServicesフォルダを作ってその配下にMailService.csクラスを作られていますか?
namespaceからそのように判断してしまっていました。

4:MailService.csのtypeof(MailService)で「MailServiceは名前空間ですが種類のように使われています。」と言われてしまい、SendMailPage.xaml.csで「this.txtFilePathの個所でそのようなものはありません。」と出てしまいました。

何度やってもできなかったのですいません。
もしよろしければアドバイス頂けないでしょうか。
お返事ありがとうございました。
よくわかりました!
ありがとうございましたe-68
Re: 実装について
コメントありがとうございます。

はい。そのとおりでございます。

通常、実行の主体となるプロジェクトのiOSプロジェクトとAndroidプロジェクトは、PCLプロジェクトを参照設定していますので、PCLプロジェクト内のクラスを呼び出すことができますが、逆の呼び出し方法(PCLから参照先)は今まではできませんでした。
それを可能にするのがDependencyServiceです。

今回の場合ですと、IMailService.csをPCL内に配置します。場所はどこでも構いませんが、DependencyServiceの利用率が多いので一か所のフォルダに固めておくとネームスペースの関係上、利用しやすいでしょう。これが無いと呼び出すことができません。

次に、Androidプロジェクト内にMailService.csを実装します。(当記事をコピペするだけです)
iOSプロジェクト内にもMailService.csを実装します。(当記事をコピペするだけです)

呼び出しはPCLでも可能ですし、実はPCL以外でもXamarin.Forms.Init()を呼び出した後であればどこからでも呼び出せます。
Main.xaml.csからページ遷移して "お問合せPage.xaml.cs"等で呼び出しすると良いでしょう。
実装について
いつも拝読させて頂いてます。
ありがとうございます。
このページのメールの設定についてなのですが、これはMain.xaml.csやMainActivity.csの他にクラスを作ってDependencyServiceを使うということなのでしょうか。
はじめのPCLチェックでプロジェクトを展開した状態から具体的にどこを変えていけばいいかよくわからなくてすいません。
もしよろしければ教えてください。
よろしくお願い致します。
PS:応援してますe-68
コメントの投稿

※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。

 入力されていないコメントには返信しませんのであらかじめご了承くださいませ。

※ニックネームでも良いので必ずご入力ください。

    

※必ずご入力ください。

    
    

※必ずご入力ください。

※技術的な質問には環境やエラーについて正確かつ詳細にお教えください。

・正確なエラーの内容

・Windowsのバージョン番号

・Visual Studioのバージョン

・機器の型番

・アプリやソフトのバージョン

    

カテゴリ別記事一覧

広告

プロフィール

石河 純


著者名 :石河 純
自己紹介:素人上がりのIT技術者。趣味は卓球・車・ボウリング

IT関連の知識はざっくりとこんな感じです。
【OS関連】
WindowsServer: 2012/2008R2/2003/2000/NT4
Windows: 10/8/7/XP/2000/me/NT4/98
Linux: CentOS RedHatLinux9
Mac: macOS Catalina 10.15 / Mojave 10.14 / High Sierra 10.13 / Sierra 10.12 / OSX Lion 10.7.5 / OSX Snow Leopard 10.6.8
【言語】
VB.net ASP.NET C#.net Java VBA
Xamarin.Forms
【データベース】
Oracle 10g/9i
SQLServer 2016/2008R2/2005/2000
SQLAnywhere 16/11/8
【BI/レポートツール】
Cognos ReportNet (IBM)
Microsoft PowerBI
ActiveReport (GrapeCity)
CrystalReport
【OCX関連】
GrapeCity InputMan SPREAD MultiRow GridView
【ネットワーク関連】
CCNP シスコ技術者認定
Cisco Catalyst シリーズ
Yamaha RTXシリーズ
FireWall関連
【WEB関連】
SEO SEM CSS jQuery IIS6/7 apache2

休みの日は卓球をやっています。
現在、卓球用品通販ショップは休業中です。