I have this error when I send an email from form in flutter.
Unhandled Exception: PlatformException(UNAVAILABLE, defualt mail app not available, null)
class _MyAppState extends State<MyApp> {
List<String> attachment = <String>[];
TextEditingController _subjectController =
TextEditingController(text: 'ct');
TextEditingController _bodyController = TextEditingController(
text: ''' a
''');
final GlobalKey<ScaffoldState> _scafoldKey = GlobalKey<ScaffoldState>();
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> send() async {
// Platform messages may fail, so we use a try/catch PlatformException.
final MailOptions mailOptions = MailOptions(
body: 'Ro',
subject: 'the Email Subject',
recipients: ['rodrigo#houlak.com'],
isHTML: true,
attachments: [ 'path/to/image.png', ],
);
await FlutterMailer.send(mailOptions);
String platformResponse;
try {
await FlutterMailer.send(mailOptions);
platformResponse = 'success';
} catch (error) {
platformResponse = error.toString();
}
if (!mounted) return;
_scafoldKey.currentState.showSnackBar(SnackBar(
content: Text(platformResponse),
));
}
I had the same issue on iPhone, it was caused because I hadn't set up the default iOS default Mail App.
Adding in AndroidManifest.xml this for me on Android solve the issue:
<application .... />
// add queries tag for mailto intent out side of application tag
<queries>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
</queries>
make sure the Android Gradle Plugin is higher then 4.1.0 you will find it inside android\build.gradle file some thing like this
dependencies { classpath 'com.android.tools.build:gradle:4.1.1' "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.4' }
2 . add this to your android/app/src/main/AndroidManifest.xml file just after where you add the <uses-permission>
<queries> <intent> <action android:name="android.intent.action.SENDTO" /> <data android:scheme="mailto" /> </intent> </queries>
run flutter clean
run flutter pub get or you can run your code it will do this for you after that Flutter email sender package should works for you
this solve the issue for me
Related
I just copied the readme file and put it into an example project, Im trying to send a email but it always have the same error.
PlatformException(not_available, No email clients found!, null, null)
There's my code:
sendMail() async {
final email = 'email';
final smtpServer = smtpserver('aa#aa.com', 'pwd');
final msg = Message()
..from = Address(email)
..recipients = ['aaa#aaa.com']
..subject = 'this works!'
..text = 'something';
String platformResponse;
try {
await send(msg, smtpServer);
platformResponse = 'success';
print(platformResponse);
} catch (error) {
print(error);
platformResponse = error.toString();
}
}
AndroidManifest.xml, it says that Android v.11 needs some permisions. So i just copy them.
I changed the package and I started to use mailer. It was more easy to use and It has similar use and more documentation.
Mailer How to use it and configure smtp
I created my own smtp.
Example of smtp:
import 'package:mailer/smtp_server.dart'
SmtpServer config_smtp(String username, String password) =>
SmtpServer('your.smtp.com',username: username,password: password);
add this in AndroidManifest.xml
<manifest package="com.mycompany.myapp">
<queries>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
</queries>
</manifest>
check here for more info
May be this package can help you. I am using this package for sending emails url_launcher: ^6.1.5. It was quite succesfull every time I used it. So if it is not important what package you should use you can try it out.
Also always recommend to test such things in real device. Sometimes it could not work on emulator
I try to send an email whenever a user clicks on an individual's email address. However, I ran into an error. I am testing through the Android emulator. Doesn't it work since there is no mail app on the emulator?
This is the error I get:
PlatformException (PlatformException(ACTIVITY_NOT_FOUND, No Activity found to handle intent { mailto:example#gmail.com?subject=Default%20subject&body=Default%20body }, null, null))
Here is the code:
sendEmail(String email) async {
String? encodeQueryParameters(Map<String, String> params) {
return params.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
}
final Uri emailLaunchUri = Uri(
scheme: 'mailto',
path: '$email',
query: encodeQueryParameters(<String, String>{
'subject': 'Default subject',
'body': 'Default body',
}));
await launch(emailLaunchUri.toString());
}
I call it like this:
onTap: () {
setState(() {
sendEmail('example#gmail.com');
});
},
I have configured Android and IOS.
For API >=30, you need to add in AndroidManifest.xml.
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>
You can find more info from Configuration section.
dependencies:
flutter_email_sender: ^5.0.2
Example:
final Email email = Email(
body: 'Email body',
subject: 'Email subject',
recipients: ['example#example.com'],
cc: ['cc#example.com'],
bcc: ['bcc#example.com'],
attachmentPaths: ['/path/to/attachment.zip'],
isHTML: false,
);
await FlutterEmailSender.send(email);
Setup:
With Android 11, package visibility is introduced that alters the ability to query installed applications and packages on a user’s device. To enable your application to get visibility into the packages you will need to add a list of queries into your AndroidManifest.xml.
<manifest package="com.mycompany.myapp">
<queries>
<intent>
<action android:name="android.intent.action.SENDTO" />
<data android:scheme="mailto" />
</intent>
</queries>
</manifest>
I use below function for handling email try using it, for sending email through android/ ios using flutter and launch function
launchMail(String toMailId, String subject, String body) async {
final Uri _emailLaunchUri = Uri(
scheme: 'mailto', path: toMailId, query: "subject=$subject&body=$body");
String a = _emailLaunchUri
.toString()
.replaceAll("+", "%20")
.replaceAll("%2520", "%20");
if (await canLaunch(a)) {
await launch(a);
} else {
throw 'Could not launch $a';
}
}
Why does it throw an error and give me the link is empty even though the link exists?
And when I use launch (url) alone, the link opens without any problems
String StateUrl = 'View App' ;
var url = 'https://www.youtube.com/watch?v=-k0IXjCHObw' ;
body: Column(
children: [
Text(StateUrl),
Center(
child: ElevatedButton.icon(
onPressed: () async{
try {
await canLaunch(url) ?
await launch(url):
throw 'Error';
} catch(e){
setState(() {
StateUrl = e.toString() ;
});
}
},
icon: const Icon(FontAwesomeIcons.link),
label: const Text('View Url')
),
),
],
),
Performing hot reload
D/EGL_emulation(17669): app_time_stats: avg=17852.65ms min=658.78ms
max=35046.52ms count=2 I/UrlLauncher(17669): component name for
https://www.youtube.com/watch?v=-k0IXjCHObw is null
D/EGL_emulation(17669): app_time_stats: avg=8279.72ms min=8279.72ms
max=8279.72ms count=1
You have to add <queries> elements to you AndroidManifest.xml file.
more info
try using
await launch(url);
instead of
if (await canLaunch(url)) { print("launching $url"); await launch(url); } else { throw 'Could not launch maps'; }
it seems theres a problem with canLaunch(url) function
With link can handle via other app like youtube, spreadsheets, document...
from android 11 (API 30) and above you must add this permission to AndroidManifest.xml
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
please refer:
https://developer.android.com/training/package-visibility/declaring
don't use canLaunch with videos URL just use try/catch
If you come here looking for why your email link (mailto:email#example.com) doesn't work, then try this out.
Don't call canLaunch for mailto links - use it only for http and https!
Since I have both http(s) and mailto links in my app, I use the try-catch block.
Here is the full function:
class UrlHandler {
/// Attempts to open the given [url] in in-app browser. Returns `true` after successful opening, `false` otherwise.
static Future<bool> open(String url) async {
try {
await launch(
url,
enableJavaScript: true,
);
return true;
} catch (e) {
log(e.toString());
return false;
}
}
}
You can use this code, it works for me. Check it out:
_launchURL() async {
const url = 'https://en.wikipedia.org/wiki/Body_mass_index';
if (await launch(url)) {
await canLaunch(url);
} else {
throw 'Could not launch $url';
}
}
and use this _launchURL() function in onPressed();
Try is like this:
try {
if(await canLaunch(url)) await launch(url):
} catch(e){
setState(() {
StateUrl = e.toString() ;
});
throw e;}
},
maybe a little late, but i also had the same problem. The solution was so set an intent in the android manifest file. If this is done, the canLaunch() call will not fail, cause you allow the android system to query this url.
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" android:host="youtube.com" />
</intent>
</queries>
For comparison, the url launcher now prints following text to the console:
I/UrlLauncher( 2628): component name for <your youtube link> is {com.google.android.youtube/com.google.android.youtube.UrlActivity}
Further if you set the launchMode to LaunchMode.externalApplication the youtube app will launch, if installed.
Hope this helps.
Also Google updates his PolicyBytes and I think using
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
or
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
might lead to app rejects, if you can not explain in detail why you need to use those permissions.
Regards Max.
The url_launcher requires a Uri object to be passed instead of a string. Add a Uri.parse
String StateUrl = 'View App' ;
var url = 'https://www.youtube.com/watch?v=-k0IXjCHObw' ;
body: Column(
children: [
Text(StateUrl),
Center(
child: ElevatedButton.icon(
onPressed: () async{
try {
Uri uri = Uri.parse(url);
await canLaunch(uri) ?
await launch(uri):
throw 'Error';
} catch(e){
setState(() {
StateUrl = e.toString() ;
});
}
},
icon: const Icon(FontAwesomeIcons.link),
label: const Text('View Url')
),
),
],
),
for me the solution is
to copy and paste
<!-- Provide required visibility configuration for API level 30 and above -->
<queries>
<!-- If your app checks for SMS support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="sms" />
</intent>
<!-- If your app checks for call support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tel" />
</intent>
</queries>
from official packages docs
but the problem is that the package removed the next lines from code snippet
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
so add them first to the
I just used this and it worked...(nb:Dec 2022)
if (!await launchUrl(url)) {
throw 'Could not launch $url';
}
Try using await launch(url); instead of
if (await canLaunch(url)) {
print("launching $url");
await launch(url);
}
else {
throw 'Could not launch maps';
}
It seems theres a problem with canLaunch(url) function
Thank you for this Solution :)
I am trying to implement passwordless email login on my app.
After the link has been clicked on, the app returns from the background but the dynamic link is null.
This is how I send the mail (with the right values for my app of course):
user.sendSignInWithEmailLink(
email: _email,
androidInstallIfNotAvailable: true,
iOSBundleID: "com.company.appname",
androidMinimumVersion: "16",
androidPackageName: "com.company.appname",
url: "https://appname.page.link/email",
handleCodeInApp: true);
I also added the intent as follows:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="appname.page.link" android:scheme="http"/>
<data android:host="appname.page.link" android:scheme="https"/>
</intent-filter>
Tried different variations with the intent, and non helped, including writing the firebase
project url as the host like: project-name.firebaseapp.com
The data still comes back empty.
Any thoughts? am I missing something?
I've updated the firebase_dynamic_links package to the latest version (0.5.0+9),
while using the configuration below and it starts working.
Sending sign-in link configuration:
firebaseAuth.sendSignInWithEmailLink(
email: email,
url: "https://mydemoapp.page.link/email",
androidInstallIfNotAvailable: true,
androidMinimumVersion: '21',
androidPackageName: 'com.example.mydemoapp'
handleCodeInApp: true,
iOSBundleID: 'com.example.mydemoapp');
AndroidManifest.xml intent-filter configuration:
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<data android:host="mydemoapp.page.link" android:scheme="https"/>
<data android:host="mydemoapp.page.link" android:scheme="http"/>
</intent-filter>
Getting a dynamic link in Flutter.
The example comes form from https://pub.dev/packages/firebase_dynamic_links
If your app did not open from a dynamic link, getInitialLink() will return null. That's the reason why you have to FirebaseDynamicLinks.instance.onLink implemented in case the app is already opened.
void main() {
runApp(MaterialApp(
title: 'Dynamic Links Example',
routes: <String, WidgetBuilder>{
'/': (BuildContext context) => MyHomeWidget(), // Default home route
'/helloworld': (BuildContext context) => MyHelloWorldWidget(),
},
));
}
class MyHomeWidgetState extends State<MyHomeWidget> {
.
.
.
#override
void initState() {
super.initState();
this.initDynamicLinks();
}
void initDynamicLinks() async {
final PendingDynamicLinkData data = await FirebaseDynamicLinks.instance.getInitialLink();
final Uri deepLink = data?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
FirebaseDynamicLinks.instance.onLink(
onSuccess: (PendingDynamicLinkData dynamicLink) async {
final Uri deepLink = dynamicLink?.link;
if (deepLink != null) {
Navigator.pushNamed(context, deepLink.path);
}
},
onError: (OnLinkErrorException e) async {
print('onLinkError');
print(e.message);
}
);
}
.
.
.
}
The mydemoapp.page.link must be added to Authorized domains in Firebase console
Is it appname.page.link or appname.page.link/email you have to specify only one email in order to achieve that
If coming to this answer in March 2022, this error is happening again and it's a bug on Flutterfire.
Here is the issue with a Pull Request that hasn't been merged yet.
I tried all packages to send email ( flutter_email_sender - flutter_mailer -url_launcher), copy and paste the example, but always the same error message : " MissingPluginException(No implementation found for methode ...), I serach a simple example to send email on press button.
thank you
To use latest version of url_launcher or above version of 4.1.0+1
, you have to migrate to android x.
[https://flutter.dev/docs/development/packages-and-plugins/androidx-compatibility][1]
Example:
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
class SendEmail extends StatelessWidget {
void _contact() async {
final url = 'mailto:dude#gmail.com';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
#override
Widget build(BuildContext context) {
return RaisedButton(
onPressed: (){_contact()},
child: Text('Mail'),
),
}
}
try adding these lines on AndroidManifest.xml
<!-- Provide required visibility configuration for API level 30 and above -->
<queries>
<!-- If your app checks for SMS support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="sms" />
</intent>
<!-- If your app checks for call support -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tel" />
</intent>
</queries>
then run flutter clean, then build again
it work for me but this is specific for url_launcher