Android: problem sending email with attachment from my application - android

My application allows users to create and modify files. I would like them to be able to send a file as an email attachment. So, I need to first create and write to a temporary file, which I then attach to the email. And then I would like to delete the temporary file when the email program finishes. Unfortunately, the gmail app responds with a result code as soon as the user clicks "send"; and if I delete the file as soon as the result code is received, no attachment is sent.
Its possible that something else is going wrong and the attachment is not sent for a different reason, but I'm pretty sure my assessment is correct because the below code works properly if I comment out the mEmailTmpFile.delete() call. It also works fine if I do something very undesirable like Thread.sleep(4000) immediately prior to mEmailTmpFile.delete().
Is there anyway to be notified when the email is done sending? Or any other suggestions for how I should work around this?
//send an email...
File externalStorage = Environment.getExternalStorageDirectory();
String sdcardPath = externalStorage.getAbsolutePath();
mEmailTmpFile = new File(sdcardPath + "/" + name );
//do some other to ensure unqiueness and then write to the file...
//all done writing, send email
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("application/zip");
sendIntent.putExtra(Intent.EXTRA_SUBJECT, name);
sendIntent.putExtra(Intent.EXTRA_TEXT, "File attached.");
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://"+ mEmailTmpFile.getPath()));
startActivityForResult(Intent.createChooser(sendIntent, "Email"), REQUESTCODE_EMAIL);
public synchronized void onActivityResult(int reqCode, int resultCode, Intent data)
{
if (reqCode == REQUESTCODE_EMAIL)
{
mEmailTmpFile.delete();
}
}

In my apps, I don't delete the temporary file. Android will take care of it by deleting the file if it needs space. I would ensure that you don't create the tmp file in the SDCard root directory since that can look messy but other than that there shouldn't be a problem.

Related

Unloaded attachment isn't marked for download error in android

I am writing phone contacts to a file and exporting it through Email intent Action. Export works fine when i write the file to SD card.But when i write the file to phone memory of the emulator i get the mail without attachment. My Log displays "Unloaded attachment isn't marked for download".
Below is my code
file = new File(ctx.getFilesDir().getAbsolutePath(),"file.txt");
if (file.exists()) {
file.delete();
}
writer = new BufferedWriter(new FileWriter(file));
for (int i = 0; i < names.size(); i++) {
writer.write(names.get(i) + "," + phnno.get(i) + "\r\n");
}
writer.flush();
writer.close();
This is my Email Intent
Uri u1 = null;
u1 = Uri.fromFile(file);
System.out.println("u1 of URI"+u1); //u1 in logcat is "file:///data/data/com.android.contactxport/files/file.txt"
Intent sendIntent = new Intent(
Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_SUBJECT,
"Mail from ContactXPort App");
sendIntent
.putExtra(Intent.EXTRA_STREAM, u1);
sendIntent.setType("text/html");
startActivity(sendIntent);
EDIT: The documnetation about unloaded attachment says
/**
* Check whether the message with a given id has unloaded attachments. If the message is
* a forwarded message, we look instead at the messages's source for the attachments. If the
* message or forward source can't be found, we return false
* #param context the caller's context
* #param messageId the id of the message
* #return whether or not the message has unloaded attachments
*/
public static boolean hasUnloadedAttachments(Context context, long messageId) {
Message msg = Message.restoreMessageWithId(context, messageId);
if (msg == null) return false;
Attachment[] atts = Attachment.restoreAttachmentsWithMessageId(context, messageId);
for (Attachment att: atts) {
if (!attachmentExists(context, att)) {
// If the attachment doesn't exist and isn't marked for download, we're in trouble
// since the outbound message will be stuck indefinitely in the Outbox. Instead,
// we'll just delete the attachment and continue; this is far better than the
// alternative. In theory, this situation shouldn't be possible.
if ((att.mFlags & (Attachment.FLAG_DOWNLOAD_FORWARD |
Attachment.FLAG_DOWNLOAD_USER_REQUEST)) == 0) {
Log.d(Logging.LOG_TAG, "Unloaded attachment isn't marked for download: " +
att.mFileName + ", #" + att.mId);
Attachment.delete(context, Attachment.CONTENT_URI, att.mId);
} else if (att.mContentUri != null) {
// In this case, the attachment file is gone from the cache; let's clear the
// contentUri; this should be a very unusual case
ContentValues cv = new ContentValues();
cv.putNull(AttachmentColumns.CONTENT_URI);
Attachment.update(context, Attachment.CONTENT_URI, att.mId, cv);
}
return true;
}
}
return false;
}
Which i understand is the path is the issue here.But the path is fyn when i printed it in log.
Any help is much appreciated.
Thanks in advance.
This is what the documentation says about internal storage:
By default, files saved to the internal storage are private to your application and other applications cannot access them (nor can the user).
So i am now trying to use the native android Email App feature of attaching file in my Application.
or i can use other back-end development technique to attach file with the contents i want to export.
From my recent experience, using Intent.EXTRA_STREAM with external file Uri -- be it located at getExternalCacheDir (), getExternalFilesDir (), or Environment.getExternalStorageDirectory () -- will effectively work with a number of email client app (probably: I only tested GMail, Evernote, and native Email client)... But notably: excepted via native Email App...
The test I have done yesterday involved native Email App against an MS Exchange corporate email account, and I received the "Unloaded attachment isn't marked for download: " debug message. The email message first looked correctly crafted, with attachment (even with attachment file size shown!), but email was sent without its attachment.
No such behaviour using GMail client: everything is fine. I would like to see attachment file size in GMail before sending it, but file is sent along with email message. On its side, Evernote creates an editable note with attachment file as an embedded object.
When I look at the reference source code you posted, I think Android native Email app developpers made slightly incorrect assumptions about attachment file. They simply didn't provide for an attachment coming from Intent.EXTRA_STREAM... Which is odd, since attachment is shown with message before sending, so it might simply just not be saved upon email creation in native email app database, or else attachment is incorrectly flagged/unflagged in the process.
I know this doesn't answer the question per se, but as for sending attachent via native Email app (so much for I can tell in Android ICS), I guess we are stuck!
I have found that for native email app to accept the attachment you need to call Intent.setType as well as using the ACTION_SEND as opposed to ACTION_SENDTO.
Here is how I ultimately constructed my intent to get email attachment to work in both gmail and native apps:
Intent intent = new Intent(Intent.ACTION_SEND); // SENDTO does not work for native email app
intent.setData(Uri.fromParts("mailto",to, null));
intent.putExtra(Intent.EXTRA_EMAIL, new String[] { to });
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, body);
intent.setType("message/email");
if (attachmentInCacheDir != null) {
intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://" + getAuthority(context) + "/" + attachmentInCacheDir.getName()));
}
context.startActivityForResult(Intent.createChooser(intent, "Send Email"), 1000);
As you can see I also am using a content provider for file access to avoid copying files to external storage. This was a whole new can of worms as the native app calls 'query' on your provider to ask for file size. If size is zero, then it wont attach. Gmail is much more lenient.

Attach an XLS (Excel) file to Email

My application uses the intent method to send out emails to users, as a convenient way of exporting Excel spreadsheet data (created by the JExcell API).
The file is contained on the SD card in a folder called records.
The file I am attempting to send is call measurments.xls.
I have tested in code for the existence of the file prior to sending. The email composer shows an attachment, but when I send and then receive the email the attachment is not there.
However, if I substitute the excel file for a png image, the attachment is received. So what gives??
Below is the code I use to send out the email, it is simply a paramiterised static method in a class by its self.
public static void sendEmailWithAttachment(Context ctx, String to,String subject, String message, String fileAndLocation)
{
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("text/plain");
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[] {to});
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, subject);
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, message);
File file = new File(fileAndLocation);
// File file = getFileStreamPath();
if (file.exists())
{
Log.v("Farmgraze", "Email file_exists!" );
}
else
{
Log.v("Farmgraze", "Email file does not exist!" );
}
Log.v("FarmGraze", "SEND EMAIL FileUri=" + Uri.parse("file:/"+ fileAndLocation));
emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:/"+ fileAndLocation));
ctx.startActivity(Intent.createChooser(emailIntent, "Send mail..."));
}//end method
So what do I need to do to receive the xls file? Change the mime types in the second line of the method's code? If so what do. Any helpful advice would be greatly appreciated.
Thanks for reading.
A.
Ok folks just to add closure to this question I found the solution.
The problem was that the file path String sent to the URI, needs to have three forward slashes.
As in:
file:///sdcard/somefolder/some_file.xls.
Also for excel documents one needs to set the type as follows:
emailIntent.setType("application/excel");
So the problem was a two pronged one. I was aware of the three slash solution via this thread, but as it did not work thought the problem lie else where.
Also I became aware of the correct mime types via this webpage which lists all of the supported mime types, and may be very useful for other readers.
So thanks for reading and taking an interest in my little problem which is now solved.
I think the issue might be with your mime-type. Try this:
MimeTypeMap mime = MimeTypeMap.getSingleton();
String mimeTypeForXLSFile = mime.getMimeTypeFromExtension(".xls");
emailIntent.setType(mimeTypeForXLSFile);

Sending Sqlite database as email attachment in Android

I have a simple app which I am using to spike sending attachments.
I have managed to send a text file from the SD card (although I couldn't get this to work with a file created in the apps private area using openFileOutput(fileName, 0)) but I now want to send a database.
By debugging I can verify the database exists and has an entry in its only table. My code to send looks like this:
gmailButton = (Button) findViewById(R.id.button);
gmailButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_SUBJECT, "subject line");
sendIntent.putExtra(Intent.EXTRA_TEXT,"Body of email");
Uri uri = Uri.fromFile(getDatabasePath("TEST_DB"));
//uri = file:///data/data/com.gmailspike/databases/TEST_DB
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
sendIntent.setType("application/octet-stream");
startActivity(Intent.createChooser(sendIntent,"Email:"));
}
})
;
However, when the email client opens the attachment has a size of 0 bytes and if I touch to open the attachment the client says the file cannot be found.
Any ideas? I'm not sure the mime type is correct, or even if it is important!
I remember having had an issue like this too, when trying to send an email with an image attachment, linking to a file stored in the apps private data folder. The attachment is just missing.
Using the mail intent opens a new application to handle the mail-creation. Therefore you either need to write a Content Provider to allow other applications access to your private data.
Or copy the content to public area first and add it to the mail intent from there (this only works when a SD-Card is present with most phones). The External Storage.getExternalStorageDirectory() could maybe used in that case.
Hope this helps to find a solution.
As for the MIME type, it is surely important, since an application has to support it (explicitly or through wildcard) to respond to the intent and to be found via createChooser.
I think Gmail for instance accepts */* as MIME type with ACTION_SEND but I don't know about other mail clients.
Edit : And as for the permission, have a look at the FLAG_GRANT_READ_URI_PERMISSION flag from the Intent class : http://developer.android.com/reference/android/content/Intent.html#FLAG_GRANT_READ_URI_PERMISSION

Android email SQLite database

I am hoping to be able to email the SQLite database I use within my app as a form of backup that the user can perform. My current code is below, the database shows up as an attachment in the email intent and the email will send, but the attachment is not sent.
File file = new File(Environment.getDataDirectory(), "/data/com.app/databases/databaseName");
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{""});
intent.putExtra(Intent.EXTRA_SUBJECT, "Backup");
intent.putExtra(Intent.EXTRA_TEXT, "");
intent.setType("application/octet-stream");
intent.putExtra(Intent.EXTRA_STREAM, file.toURI());
startActivity(Intent.createChooser(intent, "Send Email"));
Export your database to the sd card before trying to email it. You can't add attachments from within the data/data folder of your application. Those files are private to your application.
I remember I had this exact problem some time back. I'm not sure what I did to fix it, but my working code looks something like this...
File root = Environment.getExternalStorageDirectory();
String fileName = "foo.txt";
if (root.canWrite()) {
attachment = new File(root, fileName);
}
email.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(attachment));
startActivity(Intent.createChooser(email, "Send Email"));
I do remember that since I was using the SD card for storage, it would not send my attachment if I was still plugged into my computer via USB (since it kept the SD card mounted and busy). Once I unplugged the USB connection, things worked well.
https://stackoverflow.com/a/18548685/293280
The above SO Answer does a great job at showing you how to copy the DB file, email it as an attachment, and then delete the copied file. Check it out.
watch this link : http://www.openintents.org/en/node/121 you need passed URI
the solution is:
files have to be attached as
sendIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///sdcard/mysong.mp3"));
You need the extra / in file:/// (missing in the Stack Overflow post) as otherwise GMail drops the attachment just before sending stating the file path is wrong.
SO YOU NEED TH EXTRA / in file and its not droped.... hope this helps

How to attach a text file stored locally in app directory

I have an Android app that saves a text file directly onto the phone, in the app's install directory. I need to allow the user to create a new email, attaching this saved text file. When I start the intent to send the email, everything shows up in Gmail correctly, but the attachment does not get sent. All of my searches on stack overflow seem to only deal with attaching an image file from the SD card. Below is the code that I used. Please let me know if I have done something incorrectly.
File myFile = new File(getFilesDir() + "/" + "someFile.txt");
FileOutputStream stream = null;
if( file != null )
{
steam = openFileOutput("someFile.txt", Context.MODE_WORLD_READABLE);
stream.write(some_data);
Uri uri = Uri.fromFile(myFile);
Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.setType("text/plain");
sendIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
sendIntent.putExtra(Intent.EXTRA_TEXT, email_text);
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
file.close();
startActivity(Intent.createChooser(sendIntent, "Email:"));
}
I've also tried sendIntent.setType("application/octet-stream"); but that didn't make a difference. I'm at a loss for why the file doesn't attach and get sent.
Any ideas?
I've just run into exactly the same issue (wanting to attach a text file to a Gmail message). If you look in the Android log, the reason for it is:
02-28 21:01:28.434: E/Gmail(19673): file:// attachment paths must point to file:///mnt/sdcard. Ignoring attachment file:///data/data/com.stephendnicholas.gmailattach/cache/Test.txt
As a workaround, you can use a ContentProvider to provide access to files in your application's internal cache so that Gmail can attach them. I've just written up a blog post on how to do it.
Hopefully that's of some help :)
I've seen this before and the only way I could solve it was by writing the file to the SD card.
It's worth trying writing to the file to the SD card and attaching it if only to eliminate the files location as the cause of the problem.

Categories

Resources