mirror of
https://github.com/status-im/react-native-mail.git
synced 2026-08-31 03:31:13 +00:00
Merge branch 'master' of https://github.com/status-im/react-native-mail
This commit is contained in:
@@ -124,12 +124,20 @@ export default class App extends Component {
|
||||
ccRecipients: ['supportCC@example.com'],
|
||||
bccRecipients: ['supportBCC@example.com'],
|
||||
body: '<b>A Bold Body</b>',
|
||||
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,
|
||||
|
||||
+89
-76
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -1,4 +1,20 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.chirag.RNMail">
|
||||
|
||||
</manifest>
|
||||
package="com.chirag.RNMail">
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||
<data android:mimeType="*/*" />
|
||||
</intent>
|
||||
</queries>
|
||||
<application>
|
||||
<provider
|
||||
android:name=".RNMailFileProvider"
|
||||
android:authorities="${applicationId}.rnmail.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths"/>
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.chirag.RNMail;
|
||||
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
public class RNMailFileProvider extends FileProvider {
|
||||
|
||||
}
|
||||
@@ -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<ResolveInfo> resolvedIntentActivities = reactContext.getPackageManager().queryIntentActivities(i,
|
||||
PackageManager.MATCH_DEFAULT_ONLY);
|
||||
|
||||
ArrayList<Uri> uris = new ArrayList<Uri>();
|
||||
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 {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<external-path name="rnmail_dl" path="Download/" />
|
||||
<cache-path name="rnmail_cache" path="/" />
|
||||
<root-path name="rnmail_sdcard" path="." />
|
||||
</paths>
|
||||
Vendored
+23
@@ -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;
|
||||
Generated
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "react-native-mail",
|
||||
"version": "3.0.7",
|
||||
"version": "6.1.1",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
|
||||
+1
-1
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user