Karolina Hagegård
Karolina Hagegård

Reputation: 1387

How do I use the new launchUrl() method with a "mailto:" link?

I have a little link in my app that says "Send us an e-mail". When you click it, I want the default email app to open, with an email started to our email address. I used to make it do exactly that with the launch() method in the url_launcher package like this:

import 'package:url_launcher/url_launcher.dart' as url;

Future<bool?> pressedSendUsEmail() async {
  bool? success;
  try {
    print('Pressed Send us an e-mail...');
    success = await url.launch('mailto:[email protected]');  // Works like a charm...
    print('success is $success');
  } catch (e) {
    print('Caught an error in Send us an e-mail!');
    print('e is: ${e.toString()}');
  }
  return success;
}

But now, I get a warning saying launch() is deprecated! I should use launchUrl() instead. But launchUrl() doesn't take a String argument, it takes a Uri argument... and I don't know how to write this Uri correctly, so that it does what I want! I tried:

  success = await url.launchUrl(Uri(path: 'mailto:[email protected]'));

but that throws an error, because it can't interpret the ":" character. I've tried:

  success = await url.launchUrl(
    Uri.https('mailto:[email protected]', ''),
  );

and that launches the link, but in the browser... and it doesn't start up an e-mail to the pre-printed address. I tried adding:

  success = await url.launchUrl(
    Uri.https('mailto:[email protected]', ''),
    mode: url.LaunchMode.externalApplication,
  );

and that gives me an option of which external app to open the link with, but unfortunately, only browser apps are listed... not the email app!

How should I write my command to make the launchUrl() just do exactly what the old launch() did?? Most grateful for help!


Edit:

After that question was satisfactorily answered below, I now have a follow-up qn:

In another part of the app, there is a place where the user can type in a link, and I used to launch it with launch()... Is there a simple way to do that, as well?

Because in that case, I don't know if the link is gonna be a http or a https or indeed a mailto:!... and I would prefer not having to write lots of code to find that out! I just want it to try and launch the link exactly the way it's written, and so long as it's written correctly, it will work.

Upvotes: 6

Views: 9127

Answers (3)

Randal Schwartz
Randal Schwartz

Reputation: 44220

Using the service already built-in to Uri...

void _sendEmail(){
    final Uri emailLaunchUri = Uri(
        scheme: 'mailto',
        path: '[email protected]',
        queryParameters: {
            'subject': 'CallOut user Profile',
            'body': widget.userModel?.username ?? ''
        },
    );
    launchUrl(emailLaunchUri);
}

Upvotes: 8

Moshe Dicker
Moshe Dicker

Reputation: 75

The built-in query builder only work correctly for http/https.

For anything else, the following should be used, otherwise you will have "+" instead of spaces:

String? encodeQueryParameters(Map<String, String> params) {
  return params.entries
      .map((MapEntry<String, String> e) =>
          '${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
      .join('&');
}
///
void _sendEmail() {
  final Uri emailLaunchUri = Uri(
    scheme: 'mailto',
    path: '[email protected]',
    query: encodeQueryParameters({
      'subject': 'CallOut user Profile',
      'body': widget.userModel?.username ?? ''
    }),
  );
  launchUrl(emailLaunchUri);
}

Source: url_launcher Documentation

Upvotes: 2

Xuuan Thuc
Xuuan Thuc

Reputation: 2521

Try this:

void _sendEmail(){
   final Uri emailLaunchUri = Uri(
     scheme: 'mailto',
     path: '[email protected]',
     queryParameters: {
      'subject': 'CallOut user Profile',
      'body': widget.userModel?.username ?? ''
     },
    );
   launchUrl(emailLaunchUri);
}

Upvotes: 9

Related Questions