How to send email with flutter? - email

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

Related

Can't send an email through url_launcher

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';
}
}

I/UrlLauncher(17669): component name for (url) is null

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 :)

Flutter URL Launcher for HTML content is not working

I am developing an app using Flutter. Now I need to render the HTML content in my application that includes anchor links. But there is a problem with the links in the HTML content, it is not opening the links in the browser when it is clicked.
This is my code.
Container(
color: Colors.white,
padding: EdgeInsets.only(top: 10, right: 10, bottom: 10, left: 10),
child: Html(
data: htmlContent,
onLinkTap: (link) {
launch(link);
},
))
When I click on it, it is not working.
I imported this library at the top.
import 'package:url_launcher/url_launcher.dart';
What is wrong with my code and how can I fix it?
Html(
data: dataHTML,
onLinkTap: (url, _, __, ___) async {
if (await canLaunch(url!)) {
await launch(
url,
);
}
},
);
In recent versions, flutter_html, when using this event, requests more parameters that fulfill a specific task which is detailed in the documentation, but if the intention is only to launch the Urls, they can do it this way, do not forget to add the <queries> in the AndroidManifest if your app uses API 30 or higher that you specify in using url_launcher
Opening links in HTML works for me like this:
Html(
data: 'This is some link',
onLinkTap: (url) async {
if (await canLaunch(url)) {
await launch(
url,
);
} else {
throw 'Could not launch $url';
}
},
)
Note that I first await the canLaunch method before using launch to open my link.
What was your link? Would you provide us an example? Thanks!
onLinkTap: (url) async {
if (await canLaunch(url)) {
await launch(
url,
);
} else {
throw 'Could not launch $url';
}
},
Also don't forgot to add this in your Manifest file
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.SEND" />
<data android:mimeType="*/*" />
</intent>
</queries>

no permissions found in manifest for : 2 [flutter]

im using permission_handle to take permission for location.
and it always saying "No permissions found in manifest"
even i tried "flutter clean"
import 'package:permission_handler/permission_handler.dart';
class PermissionsService {
final PermissionHandler _permissionHandler = PermissionHandler();
Future<bool> _requestPermission(PermissionGroup permission) async {
var result = await _permissionHandler.requestPermissions([permission]);
if (result[permission] == PermissionStatus.granted) {
print('innnn');
return true;
}
return false;
}
Future<bool> requestLocationPermission({Function onPermissionDenied} ) async {
// return _requestPermission(PermissionGroup.locationWhenInUse);
var granted = await _requestPermission(PermissionGroup.location );
if(!granted){
onPermissionDenied();
}
return granted;
}
}
my Manifest.xml file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.artistry">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
You added permission in the Wrong Manifest File, You have to add location permission inside Android Manifest of this Directory android\app\src\main\AndroidManifest
You need to set permissions in main AndroidManifest.xml.
There are three folders debug, main and profile.
Run flutter clean.
See my example:
.../main/AndoridManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="test.packange.name">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="Test app"
android:icon="#mipmap/ic_launcher"
android:roundIcon="#mipmap/ic_launcher_round">
<activity
android:name="test.packange.name.MainActivity"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in #style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
main.dart
Future<void> requestPermission(PermissionGroup permission) async {
final List<PermissionGroup> permissions = <PermissionGroup>[permission];
final Map<PermissionGroup, PermissionStatus> permissionRequestResult =
await PermissionHandler().requestPermissions(permissions);
print(permissionRequestResult);
_permissionStatus = permissionRequestResult[permission];
if (_permissionStatus == PermissionStatus.granted) {
initLocationStreamer();
}
print(_permissionStatus);
}
Update plugin https://github.com/Baseflow/flutter-permission-handler. See example and issues.

Flutter email sender

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