【Flutter/Dart】メールアプリをアプリ内で起動してメールを送信する(flutter_email_sender)

目次

概要

Flutterを使用していて、時にサービスの内容をユーザーに通知したりするときもあるだろう。
そんなときはFlutterで入力した内容を元にメールアプリを起動することができる。
手段は二つ。

  • Flutterアプリ内でメールアプリを起動する
  • Flutterアプリからメールアプリに切り替える

これはWebブラウザでも、アプリ内でWebページを表示するか、ブラウザで表示するかのようなものだ。

今回は、「Flutterアプリ内でメールアプリを起動する」というものをやってみ

実装方法

メール送信に必要なパッケージを追加する

dependencies:
  flutter:
    sdk: flutter
    flutter_email_sender: ^6.0.2

追加したら以下のコマンドを実行してパッケージのインストール状態を更新しよう。

$ flutter pub upgrade

ソースコード

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'SendMailView/SendMailView.dart';

void main() async{

  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
        useMaterial3: true,
      ),
      home: SendMailView(),
    );
  }
}
import 'package:flutter_riverpod/flutter_riverpod.dart';

final sendMailModelProvider = Provider((ref) => SendMailModel());

class SendMailModel {

}
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'SendMailModel.dart';

final sendMailRepositoryProvider = Provider((ref) => SendMailRepositoryImpl(model: ref.read(sendMailModelProvider)));

abstract class SendMailRepository {

}

class SendMailRepositoryImpl implements SendMailRepository {
  SendMailRepositoryImpl({required SendMailModel model}): _model = model;

  final SendMailModel _model;
}
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import 'SendMailViewModel.dart';

class SendMailView extends ConsumerWidget {
  SendMailView({Key? key}) : super(key: key);
  SendMailViewModel _viewModel = SendMailViewModel();

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    return Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: const Text("メールを送ろう"),
        ),
        body: Builder(
            builder: ((context) => SingleChildScrollView(
                child: Column(
                    children: [
                      _sendTo(),
                      _mailTitle(),
                      _carbonCopiesTextField(),
                      _blindCarbonCopiesTextField(),
                      _mailMassage(),
                      _sendButton()
                    ]
                )
            ))
        )
    );
  }

  Widget _sendTo() {
    return Column(
      children: [
        const Text("宛先"),
        TextField(
          controller: _viewModel.recipientsEditingController,
          obscureText: false,
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
            labelText: "",
          ),
        )
      ],
    );
  }

  Widget _mailTitle() {
    return Column(
      children: [
        const Text("件名"),
        TextField(
          controller: _viewModel.titleEditingController,
          obscureText: false,
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
            labelText: "",
          ),
        )
      ],
    );
  }

  Widget _carbonCopiesTextField() {
    return Column(
      children: [
        const Text("CC:"),
        TextField(
          controller: _viewModel.carbonCopiesEditingController,
          obscureText: false,
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
            labelText: "",
          ),
        )
      ],
    );
  }

  Widget _blindCarbonCopiesTextField() {
    return Column(
      children: [
        const Text("BCC:"),
        TextField(
          controller: _viewModel.blindCarbonCopiesEditingController,
          obscureText: false,
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
            labelText: "",
          ),
        )
      ],
    );
  }

  Widget _mailMassage() {
    return Column(
      children: [
        const Text("本文"),
        TextField(
          controller: _viewModel.mailBodyEditingController,
          obscureText: false,
          maxLines: 6,
          keyboardType: TextInputType.multiline,
          decoration: const InputDecoration(
            border: OutlineInputBorder(),
            labelText: "",
          ),
        ),
      ],
    );
  }

  Widget _sendButton() {
    return OutlinedButton(
        onPressed: () { _viewModel.sendMail(); },
        child: const Text("送信")
    );
  }
}
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_email_sender/flutter_email_sender.dart';

import 'SendMailRepository.dart';

final sendMailViewModelProvider = ChangeNotifierProvider((ref) => SendMailViewModel(repository: ref.read(sendMailRepositoryProvider)));

class SendMailViewModel extends ChangeNotifier {
  SendMailRepository? repository;

  var recipientsEditingController = TextEditingController();
  var titleEditingController = TextEditingController();
  var carbonCopiesEditingController = TextEditingController();
  var blindCarbonCopiesEditingController = TextEditingController();
  var mailBodyEditingController = TextEditingController();

  SendMailViewModel({this.repository}) {

  }

  void sendMail()  {
    openMailApp();
  }

  void openMailApp() async {
    var recipients = recipientsEditingController.text.split(",");
    var carbonCopies = carbonCopiesEditingController.text.split(",");
    var blindCarbonCopies = blindCarbonCopiesEditingController.text.split(",");

    try {
      final emailData = Email(
        body: mailBodyEditingController.text,
        subject: titleEditingController.text,
        recipients: recipients,
        cc: carbonCopies,
        bcc: blindCarbonCopies,
        attachmentPaths: []
      );

      await FlutterEmailSender.send(emailData);
      print('送信成功');
    } catch (e) {
      print(e);
    }
  }
}

デモ動画

詳細

今回の目玉はこれだ。

まずはインストールしたパッケージをimportしよう。
これを書かないとメールアプリを立ち上げるのに必要なものが使えない。

import 'package:flutter_email_sender/flutter_email_sender.dart';

その後、Emailオブジェクトを生成する。
そして、そのEmailオブジェクトのsendメソッドの引数に渡すことで、Flutterアプリ内でメールアプリを立ち上げることができる。

Swiftのpresentメソッドを使用した時の画面遷移のように表示される。

try {
  final emailData = Email(
    body: mailBodyEditingController.text,
    subject: titleEditingController.text,
    recipients: recipients,
    cc: carbonCopies,
    bcc: blindCarbonCopies,
    attachmentPaths: []
  );

  await FlutterEmailSender.send(emailData);
  print('送信成功');
} catch (e) {
  print(e);
}

設定内容は以下のようになる。

引数名(キー名)内容
bodyメール本文
subjectメールの件名
recipientsメールの宛先
List<String>型で格納する
ccCCの宛先。
List<String>型で格納する
bccBCCの宛先。
List<String>型で格納する
attachmentPaths添付ファイルのパス

このように、至ってシンプルだ。
加えて、アプリ内でメールアプリが立ち上がるので、開発中のアプリの操作を続けた状態になるもで、ユーザーにも優しい。

参考ページ