diff --git a/README.md b/README.md
index 3bf1f4c..819cc10 100644
--- a/README.md
+++ b/README.md
@@ -124,12 +124,20 @@ export default class App extends Component {
ccRecipients: ['supportCC@example.com'],
bccRecipients: ['supportBCC@example.com'],
body: 'A Bold Body',
+ customChooserTitle: 'This is my new title', // Android only (defaults to "Send Mail")
isHTML: true,
- attachment: {
- path: '', // The absolute path of the file from which to read data.
- type: '', // Mime Type: jpg, png, doc, ppt, html, pdf, csv
- name: '', // Optional: Custom filename for attachment
- }
+ attachments: [{
+ // Specify either `path` or `uri` to indicate where to find the file data.
+ // The API used to create or locate the file will usually indicate which it returns.
+ // An absolute path will look like: /cacheDir/photos/some image.jpg
+ // A URI starts with a protocol and looks like: content://appname/cacheDir/photos/some%20image.jpg
+ path: '', // The absolute path of the file from which to read data.
+ uri: '', // The uri of the file from which to read the data.
+ // Specify either `type` or `mimeType` to indicate the type of data.
+ type: '', // Mime Type: jpg, png, doc, ppt, html, pdf, csv
+ mimeType: '', // - use only if you want to use custom type
+ name: '', // Optional: Custom filename for attachment
+ }]
}, (error, event) => {
Alert.alert(
error,
diff --git a/RNMail/RNMail.m b/RNMail/RNMail.m
index 7e97c42..7c77eac 100644
--- a/RNMail/RNMail.m
+++ b/RNMail/RNMail.m
@@ -36,108 +36,121 @@ RCT_EXPORT_METHOD(mail:(NSDictionary *)options
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
mail.mailComposeDelegate = self;
_callbacks[RCTKeyForInstance(mail)] = callback;
-
+
if (options[@"subject"]){
NSString *subject = [RCTConvert NSString:options[@"subject"]];
[mail setSubject:subject];
}
-
- bool *isHTML = NO;
-
+
+ BOOL isHTML = NO;
+
if (options[@"isHTML"]){
isHTML = [options[@"isHTML"] boolValue];
}
-
+
if (options[@"body"]){
NSString *body = [RCTConvert NSString:options[@"body"]];
[mail setMessageBody:body isHTML:isHTML];
}
-
+
if (options[@"recipients"]){
NSArray *recipients = [RCTConvert NSArray:options[@"recipients"]];
[mail setToRecipients:recipients];
}
-
+
if (options[@"ccRecipients"]){
NSArray *ccRecipients = [RCTConvert NSArray:options[@"ccRecipients"]];
[mail setCcRecipients:ccRecipients];
}
-
+
if (options[@"bccRecipients"]){
NSArray *bccRecipients = [RCTConvert NSArray:options[@"bccRecipients"]];
[mail setBccRecipients:bccRecipients];
}
-
- if (options[@"attachment"] && options[@"attachment"][@"path"] && options[@"attachment"][@"type"]){
- NSString *attachmentPath = [RCTConvert NSString:options[@"attachment"][@"path"]];
- NSString *attachmentType = [RCTConvert NSString:options[@"attachment"][@"type"]];
- NSString *attachmentName = [RCTConvert NSString:options[@"attachment"][@"name"]];
-
- // Set default filename if not specificed
- if (!attachmentName) {
- attachmentName = [[attachmentPath lastPathComponent] stringByDeletingPathExtension];
+ if (options[@"attachments"]) {
+ NSArray *attachments = [RCTConvert NSArray:options[@"attachments"]];
+ for (NSDictionary *attachment in attachments) {
+ if ((attachment[@"path"] || attachment[@"uri"]) && (attachment[@"type"] || attachment[@"mimeType"])) {
+ NSString *attachmentPath = [RCTConvert NSString:attachment[@"path"]];
+ NSString *attachmentUri = [RCTConvert NSString:attachment[@"uri"]];
+ NSString *attachmentType = [RCTConvert NSString:attachment[@"type"]];
+ NSString *attachmentName = [RCTConvert NSString:attachment[@"name"]];
+ NSString *attachmentMimeType = [RCTConvert NSString:attachment[@"mimeType"]];
+
+ // Set default filename if not specificed
+ if (!attachmentName) {
+ attachmentName = [[attachmentPath lastPathComponent] stringByDeletingPathExtension];
+ }
+
+ NSData *fileData;
+ if (attachmentPath) {
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ if (![fileManager fileExistsAtPath:attachmentPath]){
+ callback(@[[NSString stringWithFormat: @"attachment file with path '%@' does not exist", attachmentPath]]);
+ return;
+ }
+ // Get the resource path and read the file using NSData
+ fileData = [NSData dataWithContentsOfFile:attachmentPath];
+ } else if (attachmentUri) {
+ // Get the URI and read it using NSData
+ NSURL *attachmentURL = [[NSURLComponents componentsWithString:attachmentUri] URL];
+ NSError *error = nil;
+ fileData = [NSData dataWithContentsOfURL:attachmentURL options:0 error:&error];
+ if (!fileData) {
+ callback(@[[NSString stringWithFormat: @"attachment file with uri '%@' does not exist", attachmentUri]]);
+ return;
+ }
+ }
+
+ // Determine the MIME type
+ NSString *mimeType;
+ if (attachmentType) {
+ /*
+ * Add additional mime types and PR if necessary. Find the list
+ * of supported formats at http://www.iana.org/assignments/media-types/media-types.xhtml
+ */
+ NSDictionary *supportedMimeTypes = @{
+ @"jpeg" : @"image/jpeg",
+ @"jpg" : @"image/jpeg",
+ @"png" : @"image/png",
+ @"doc" : @"application/msword",
+ @"docx" : @"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ @"ppt" : @"application/vnd.ms-powerpoint",
+ @"pptx" : @"application/vnd.openxmlformats-officedocument.presentationml.presentation",
+ @"html" : @"text/html",
+ @"csv" : @"text/csv",
+ @"pdf" : @"application/pdf",
+ @"vcard" : @"text/vcard",
+ @"json" : @"application/json",
+ @"zip" : @"application/zip",
+ @"text" : @"text/*",
+ @"mp3" : @"audio/mpeg",
+ @"wav" : @"audio/wav",
+ @"aiff" : @"audio/aiff",
+ @"flac" : @"audio/flac",
+ @"ogg" : @"audio/ogg",
+ @"xls" : @"application/vnd.ms-excel",
+ @"ics" : @"text/calendar",
+ @"xlsx" : @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+ };
+ if([supportedMimeTypes objectForKey:attachmentType]) {
+ mimeType = [supportedMimeTypes objectForKey:attachmentType];
+ } else {
+ callback(@[[NSString stringWithFormat: @"Mime type '%@' for attachment is not handled", attachmentType]]);
+ return;
+ }
+ } else if (attachmentMimeType) {
+ mimeType = attachmentMimeType;
+ }
+
+ // Add attachment
+ [mail addAttachmentData:fileData mimeType:mimeType fileName:attachmentName];
+ }
}
-
- // Get the resource path and read the file using NSData
- NSData *fileData = [NSData dataWithContentsOfFile:attachmentPath];
-
- // Determine the MIME type
- NSString *mimeType;
-
- /*
- * Add additional mime types and PR if necessary. Find the list
- * of supported formats at http://www.iana.org/assignments/media-types/media-types.xhtml
- */
- if ([attachmentType isEqualToString:@"jpg"]) {
- mimeType = @"image/jpeg";
- } else if ([attachmentType isEqualToString:@"png"]) {
- mimeType = @"image/png";
- } else if ([attachmentType isEqualToString:@"doc"]) {
- mimeType = @"application/msword";
- } else if ([attachmentType isEqualToString:@"docx"]) {
- mimeType = @"application/vnd.openxmlformats-officedocument.wordprocessingml.document";
- } else if ([attachmentType isEqualToString:@"ppt"]) {
- mimeType = @"application/vnd.ms-powerpoint";
- } else if ([attachmentType isEqualToString:@"pptx"]) {
- mimeType = @"application/vnd.openxmlformats-officedocument.presentationml.presentation";
- } else if ([attachmentType isEqualToString:@"html"]) {
- mimeType = @"text/html";
- } else if ([attachmentType isEqualToString:@"csv"]) {
- mimeType = @"text/csv";
- } else if ([attachmentType isEqualToString:@"pdf"]) {
- mimeType = @"application/pdf";
- } else if ([attachmentType isEqualToString:@"vcard"]) {
- mimeType = @"text/vcard";
- } else if ([attachmentType isEqualToString:@"json"]) {
- mimeType = @"application/json";
- } else if ([attachmentType isEqualToString:@"zip"]) {
- mimeType = @"application/zip";
- } else if ([attachmentType isEqualToString:@"text"]) {
- mimeType = @"text/*";
- } else if ([attachmentType isEqualToString:@"mp3"]) {
- mimeType = @"audio/mpeg";
- } else if ([attachmentType isEqualToString:@"wav"]) {
- mimeType = @"audio/wav";
- } else if ([attachmentType isEqualToString:@"aiff"]) {
- mimeType = @"audio/aiff";
- } else if ([attachmentType isEqualToString:@"flac"]) {
- mimeType = @"audio/flac";
- } else if ([attachmentType isEqualToString:@"ogg"]) {
- mimeType = @"audio/ogg";
- } else if ([attachmentType isEqualToString:@"xls"]) {
- mimeType = @"application/vnd.ms-excel";
- } else if ([attachmentType isEqualToString:@"ics"]) {
- mimeType = @"text/calendar";
- } else if ([attachmentType isEqualToString:@"xlsx"]) {
- mimeType = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
- }
-
- // Add attachment
- [mail addAttachmentData:fileData mimeType:mimeType fileName:attachmentName];
}
-
+
UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
-
+
while (root.presentedViewController) {
root = root.presentedViewController;
}
diff --git a/android/build.gradle b/android/build.gradle
index 9305052..df12459 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -9,7 +9,7 @@ android {
buildToolsVersion project.hasProperty('buildToolsVersion') ? project.buildToolsVersion : "23.0.1"
defaultConfig {
- minSdkVersion 16
+ minSdkVersion 21
targetSdkVersion project.hasProperty('targetSdkVersion') ? project.targetSdkVersion : 22
versionCode 1
versionName "1.0"
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 914eec5..7a86d24 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,4 +1,20 @@
-
-
\ No newline at end of file
+ package="com.chirag.RNMail">
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/src/main/java/com/chirag/RNMail/RNMailFileProvider.java b/android/src/main/java/com/chirag/RNMail/RNMailFileProvider.java
new file mode 100644
index 0000000..45cf23e
--- /dev/null
+++ b/android/src/main/java/com/chirag/RNMail/RNMailFileProvider.java
@@ -0,0 +1,7 @@
+package com.chirag.RNMail;
+
+import androidx.core.content.FileProvider;
+
+public class RNMailFileProvider extends FileProvider {
+
+}
diff --git a/android/src/main/java/com/chirag/RNMail/RNMailModule.java b/android/src/main/java/com/chirag/RNMail/RNMailModule.java
index a0cb478..e93973e 100644
--- a/android/src/main/java/com/chirag/RNMail/RNMailModule.java
+++ b/android/src/main/java/com/chirag/RNMail/RNMailModule.java
@@ -5,6 +5,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.text.Html;
+import androidx.core.content.FileProvider;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
@@ -15,10 +16,8 @@ import com.facebook.react.bridge.Callback;
import java.util.List;
import java.io.File;
-
-import android.app.Activity;
-import android.support.v4.content.FileProvider;
-import android.os.Build;
+import java.net.URI;
+import java.util.ArrayList;
/**
* NativeModule that allows JS to open emails sending apps chooser.
@@ -55,37 +54,11 @@ public class RNMailModule extends ReactContextBaseJavaModule {
return strArray;
}
- private Intent getIntent() {
- Intent i;
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- // https://stackoverflow.com/a/42856167
- Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
- emailSelectorIntent.setData(Uri.parse("mailto:"));
-
- i = new Intent(Intent.ACTION_SEND);
- i.setData(Uri.parse("mailto:"));
- i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- i.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
- i.setSelector( emailSelectorIntent );
- } else {
- i = new Intent(Intent.ACTION_SEND);
- i.setPackage("com.google.android.gm");
- }
-
- return i;
- }
-
- private Uri getFileUri(String path) {
- File file = new File(path);
- file.setReadable(true, false);
- final String providerName = reactContext.getPackageName() + ".provider";
- final Activity activity = getCurrentActivity();
- return FileProvider.getUriForFile(activity, providerName, file);
- }
-
@ReactMethod
public void mail(ReadableMap options, Callback callback) {
- Intent i = getIntent();
+ Intent i = new Intent(Intent.ACTION_SEND_MULTIPLE);
+ Intent selectorIntent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"));
+ i.setSelector(selectorIntent);
if (options.hasKey("subject") && !options.isNull("subject")) {
i.putExtra(Intent.EXTRA_SUBJECT, options.getString("subject"));
@@ -115,13 +88,40 @@ public class RNMailModule extends ReactContextBaseJavaModule {
i.putExtra(Intent.EXTRA_BCC, readableArrayToStringArray(bccRecipients));
}
- if (options.hasKey("attachment") && !options.isNull("attachment")) {
- ReadableMap attachment = options.getMap("attachment");
- if (attachment.hasKey("path") && !attachment.isNull("path")) {
- String path = attachment.getString("path");
- final Uri p = getFileUri(path);
- i.putExtra(Intent.EXTRA_STREAM, p);
+ if (options.hasKey("attachments") && !options.isNull("attachments")) {
+ ReadableArray r = options.getArray("attachments");
+ int length = r.size();
+
+ String provider = reactContext.getApplicationContext().getPackageName() + ".rnmail.provider";
+ List resolvedIntentActivities = reactContext.getPackageManager().queryIntentActivities(i,
+ PackageManager.MATCH_DEFAULT_ONLY);
+
+ ArrayList uris = new ArrayList();
+ for (int keyIndex = 0; keyIndex < length; keyIndex++) {
+ ReadableMap clip = r.getMap(keyIndex);
+ Uri uri;
+ if (clip.hasKey("path") && !clip.isNull("path")) {
+ String path = clip.getString("path");
+ File file = new File(path);
+ uri = FileProvider.getUriForFile(reactContext, provider, file);
+ } else if (clip.hasKey("uri") && !clip.isNull("uri")) {
+ String uriPath = clip.getString("uri");
+ uri = Uri.parse(uriPath);
+ } else {
+ callback.invoke("not_found");
+ return;
+ }
+ uris.add(uri);
+
+ for (ResolveInfo resolvedIntentInfo : resolvedIntentActivities) {
+ String packageName = resolvedIntentInfo.activityInfo.packageName;
+ reactContext.grantUriPermission(packageName, uri,
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
}
+
+ i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ i.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
}
PackageManager manager = reactContext.getPackageManager();
@@ -140,7 +140,13 @@ public class RNMailModule extends ReactContextBaseJavaModule {
callback.invoke("error");
}
} else {
- Intent chooser = Intent.createChooser(i, "Send Mail");
+ String chooserTitle = "Send Mail";
+
+ if (options.hasKey("customChooserTitle") && !options.isNull("customChooserTitle")) {
+ chooserTitle = options.getString("customChooserTitle");
+ }
+
+ Intent chooser = Intent.createChooser(i, chooserTitle);
chooser.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
diff --git a/android/src/main/res/xml/provider_paths.xml b/android/src/main/res/xml/provider_paths.xml
new file mode 100644
index 0000000..97384e1
--- /dev/null
+++ b/android/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/index.d.ts b/index.d.ts
new file mode 100644
index 0000000..765abbc
--- /dev/null
+++ b/index.d.ts
@@ -0,0 +1,23 @@
+export namespace Mailer {
+ function mail(options: {
+ subject?: string;
+ recipients?: string[];
+ ccRecipients?: string[];
+ bccRecipients?: string[];
+ body?: string;
+ customChooserTitle?: string;
+ isHTML?: boolean;
+ attachments?: {
+ path?: string; // Specify either 'path' or 'uri'
+ uri?: string;
+ type?: string; // Specify either 'type' or 'mimeType'
+ mimeType?: string;
+ name?: string;
+ }[]
+ }, callback: (
+ error: string,
+ event?: string
+ ) => void): void;
+}
+
+export default Mailer;
diff --git a/package-lock.json b/package-lock.json
index df4c0f3..9157b08 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,5 +1,5 @@
{
"name": "react-native-mail",
- "version": "3.0.7",
+ "version": "6.1.1",
"lockfileVersion": 1
}
diff --git a/package.json b/package.json
index 6ce0769..e2d84df 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-native-mail",
- "version": "3.0.7",
+ "version": "6.1.1",
"description": "A wrapper on top of MFMailComposeViewController from iOS and Mail Intent on android",
"author": {
"name": "Chirag Jain",
diff --git a/react-native-mail.podspec b/react-native-mail.podspec
index e31b682..41d4683 100644
--- a/react-native-mail.podspec
+++ b/react-native-mail.podspec
@@ -13,6 +13,6 @@ Pod::Spec.new do |s|
s.source = { :git => "https://github.com/chirag04/react-native-mail", :tag => "v#{s.version}" }
s.source_files = 'RNMail/*.{h,m}'
- s.dependency 'React'
+ s.dependency 'React-Core'
end