1

The javadocs for the Message.setAttachment() method say "Sets the message attachment if exists", which means it will silently fail if the file doesn't exist.

The if() statement in my code ensures that Message.setAttachment() won't get called unless the file exists. But the email arrives, so I know the file exists and setAttachment is getting called. I also know that it's 15823 bytes long, because the email tells me this. But nothing has been attached. Two months ago, this worked fine. Am I doing something wrong? Or is this a fresh bug in the setAttachment() method?

String imageFile = appHomePath + baseName;
try (OutputStream os = FileSystemStorage.getInstance().openOutputStream(imageFile)) {
  ImageIO.getImageIO().save(screenShot, os, ImageIO.FORMAT_PNG, 1);
}
if (FileSystemStorage.getInstance().exists(imageFile)) {
  long size = FileSystemStorage.getInstance().getLength(imageFile);
  Message emailMessage = new Message(imageFile + "\n\n" + size + " bytes\n" + notes);
  emailMessage.setAttachment(imageFile);
  //  emailMessage.setAttachment("file://" + imageFile); // Didn't work either
  emailMessage.setMimeType("image/png");
  String[] recipients = {"SwingGuy1024@yahoo.com"};
  Message.sendMessage(recipients, "Snap", emailMessage);
} else {
  Dialog.show("Missing file", "Missing: "+imageFile, Dialog.TYPE_ERROR, null, "OK", null);
}

Addendum: Here's a pair of stack traces that I'm getting: (I should mention that I don't understand why the FileNotFoundException gives a path that's not what I specified. The path I specified is logged in the second line below, as image file path:)

D/EmailAttachmentTest(12124): [EDT] 0:0:13,592 - appHomePath: /data/data/com.mycompany.myapp/files/
D/EmailAttachmentTest(12124): [EDT] 0:0:13,614 - image file path: /data/data/com.mycompany.myapp/files/snapshot19.png
D/EmailAttachmentTest(12124): [EDT] 0:0:13,852 - Attachments: 1
D/EmailAttachmentTest(12124): [EDT] 0:0:13,853 - Attachment: /data/data/com.mycompany.myapp/files/snapshot19.png maps to image/png
W/ResourceType(12124): No package identifier when getting value for resource number 0x00000000
W/ResourceType(12124): No package identifier when getting value for resource number 0x00000000
W/ResourceType(12124): No package identifier when getting value for resource number 0x00000000
W/ResourceType(12124): No package identifier when getting value for resource number 0x00000000
W/ResourceType(12124): No package identifier when getting value for resource number 0x00000000
E/AndroidImplementation(12124): null
E/AndroidImplementation(12124): java.io.FileNotFoundException: /storage/emulated/legacy/tmp/snapshot19.png: open failed: EACCES (Permission denied)
E/AndroidImplementation(12124):     at libcore.io.IoBridge.open(IoBridge.java:456)
E/AndroidImplementation(12124):     at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
E/AndroidImplementation(12124):     at java.io.FileOutputStream.<init>(FileOutputStream.java:127)
E/AndroidImplementation(12124):     at java.io.FileOutputStream.<init>(FileOutputStream.java:116)
E/AndroidImplementation(12124):     at com.codename1.impl.android.AndroidImplementation.createFileOuputStream(AndroidImplementation.java:4380)
E/AndroidImplementation(12124):     at com.codename1.impl.android.AndroidImplementation.openFileOutputStream(AndroidImplementation.java:4301)
E/AndroidImplementation(12124):     at com.codename1.io.FileSystemStorage.openOutputStream(FileSystemStorage.java:274)
E/AndroidImplementation(12124):     at com.codename1.impl.android.AndroidImplementation.fixAttachmentPath(AndroidImplementation.java:4485)
E/AndroidImplementation(12124):     at com.codename1.impl.android.AndroidImplementation.sendMessage(AndroidImplementation.java:4537)
E/AndroidImplementation(12124):     at com.codename1.ui.Display.sendMessage(Display.java:3252)
E/AndroidImplementation(12124):     at com.codename1.messaging.Message.sendMessage(Message.java:159)
E/AndroidImplementation(12124):     at com.mycompany.myapp.EmailAttachmentTest$MainForm.saveSnapshot(EmailAttachmentTest.java:249)
E/AndroidImplementation(12124):     at com.mycompany.myapp.EmailAttachmentTest$MainForm.dumpScreen(EmailAttachmentTest.java:206)
E/AndroidImplementation(12124):     at com.mycompany.myapp.EmailAttachmentTest$MainForm.lambda$new$0(EmailAttachmentTest.java:93)
E/AndroidImplementation(12124):     at com.mycompany.myapp.EmailAttachmentTest$MainForm.access$lambda$1(EmailAttachmentTest.java)
E/AndroidImplementation(12124):     at com.mycompany.myapp.EmailAttachmentTest$MainForm$$Lambda$2.actionPerformed(Unknown Source)
E/AndroidImplementation(12124):     at com.codename1.ui.util.EventDispatcher.fireActionEvent(EventDispatcher.java:349)
E/AndroidImplementation(12124):     at com.codename1.ui.Button.fireActionEvent(Button.java:411)
E/AndroidImplementation(12124):     at com.codename1.ui.Button.released(Button.java:442)
E/AndroidImplementation(12124):     at com.codename1.ui.Button.pointerReleased(Button.java:530)
E/AndroidImplementation(12124):     at com.codename1.ui.Form.pointerReleased(Form.java:2620)
E/AndroidImplementation(12124):     at com.codename1.ui.Form.pointerReleased(Form.java:2556)
E/AndroidImplementation(12124):     at com.codename1.ui.Component.pointerReleased(Component.java:3147)
E/AndroidImplementation(12124):     at com.codename1.ui.Display.handleEvent(Display.java:2024)
E/AndroidImplementation(12124):     at com.codename1.ui.Display.edtLoopImpl(Display.java:1066)
E/AndroidImplementation(12124):     at com.codename1.ui.Display.mainEDTLoop(Display.java:995)
E/AndroidImplementation(12124):     at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
E/AndroidImplementation(12124):     at com.codename1.impl.CodenameOneThread$1.run(CodenameOneThread.java:60)
E/AndroidImplementation(12124):     at java.lang.Thread.run(Thread.java:818)
E/AndroidImplementation(12124): Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
E/AndroidImplementation(12124):     at libcore.io.Posix.open(Native Method)
E/AndroidImplementation(12124):     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
E/AndroidImplementation(12124):     at libcore.io.IoBridge.open(IoBridge.java:442)
E/AndroidImplementation(12124):     ... 28 more
W/Bundle  (12124): Key android.intent.extra.TEXT expected ArrayList<CharSequence> but value was a java.lang.String.  The default value <null> was returned.
W/Bundle  (12124): Attempt to cast generated internal exception:
W/Bundle  (12124): java.lang.ClassCastException: java.lang.String cannot be cast to java.util.ArrayList
W/Bundle  (12124):  at android.os.BaseBundle.getCharSequenceArrayList(BaseBundle.java:1060)
W/Bundle  (12124):  at android.os.Bundle.getCharSequenceArrayList(Bundle.java:884)
W/Bundle  (12124):  at android.content.Intent.getCharSequenceArrayListExtra(Intent.java:5182)
W/Bundle  (12124):  at android.content.Intent.migrateExtraStreamToClipData(Intent.java:7865)
W/Bundle  (12124):  at android.content.Intent.migrateExtraStreamToClipData(Intent.java:7828)
W/Bundle  (12124):  at android.app.Instrumentation.execStartActivity(Instrumentation.java:1561)
W/Bundle  (12124):  at android.app.Activity.startActivityForResult(Activity.java:3755)
W/Bundle  (12124):  at android.app.Activity.startActivityForResult(Activity.java:3716)
W/Bundle  (12124):  at com.codename1.impl.android.CodenameOneActivity.startActivityForResult(CodenameOneActivity.java:541)
W/Bundle  (12124):  at com.codename1.impl.android.AndroidNativeUtil.startActivityForResult(AndroidNativeUtil.java:140)
W/Bundle  (12124):  at com.codename1.impl.android.AndroidImplementation.sendMessage(AndroidImplementation.java:4566)
W/Bundle  (12124):  at com.codename1.ui.Display.sendMessage(Display.java:3252)
W/Bundle  (12124):  at com.codename1.messaging.Message.sendMessage(Message.java:159)
W/Bundle  (12124):  at com.mycompany.myapp.EmailAttachmentTest$MainForm.saveSnapshot(EmailAttachmentTest.java:249)
W/Bundle  (12124):  at com.mycompany.myapp.EmailAttachmentTest$MainForm.dumpScreen(EmailAttachmentTest.java:206)
W/Bundle  (12124):  at com.mycompany.myapp.EmailAttachmentTest$MainForm.lambda$new$0(EmailAttachmentTest.java:93)
W/Bundle  (12124):  at com.mycompany.myapp.EmailAttachmentTest$MainForm.access$lambda$1(EmailAttachmentTest.java)
W/Bundle  (12124):  at com.mycompany.myapp.EmailAttachmentTest$MainForm$$Lambda$2.actionPerformed(Unknown Source)
W/Bundle  (12124):  at com.codename1.ui.util.EventDispatcher.fireActionEvent(EventDispatcher.java:349)
W/Bundle  (12124):  at com.codename1.ui.Button.fireActionEvent(Button.java:411)
W/Bundle  (12124):  at com.codename1.ui.Button.released(Button.java:442)
W/Bundle  (12124):  at com.codename1.ui.Button.pointerReleased(Button.java:530)
W/Bundle  (12124):  at com.codename1.ui.Form.pointerReleased(Form.java:2620)
W/Bundle  (12124):  at com.codename1.ui.Form.pointerReleased(Form.java:2556)
W/Bundle  (12124):  at com.codename1.ui.Component.pointerReleased(Component.java:3147)
W/Bundle  (12124):  at com.codename1.ui.Display.handleEvent(Display.java:2024)
W/Bundle  (12124):  at com.codename1.ui.Display.edtLoopImpl(Display.java:1066)
W/Bundle  (12124):  at com.codename1.ui.Display.mainEDTLoop(Display.java:995)
W/Bundle  (12124):  at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
W/Bundle  (12124):  at com.codename1.impl.CodenameOneThread$1.run(CodenameOneThread.java:60)
W/Bundle  (12124):  at java.lang.Thread.run(Thread.java:818)
MiguelMunoz
  • 4,548
  • 3
  • 34
  • 51
  • I just tried your code and it worked on my android, maybe it's a specific device issue? try with a different device – Chen May 19 '16 at 07:11
  • Unfortunately, I don't have another device. I'm using a Moto E (2nd Generation) with Android 5.1 I did discover that I my call to setMimeType() was wrong. It needed to be setAttachmentMimeType(), but that didn't fix anything. This is very frustrating. I'm using code that used to work on my phone, that works on other people's phone, but nobody can reproduce the bug to fix it. – MiguelMunoz May 20 '16 at 20:24

1 Answers1

0

On which OS?

If this is on Android then it's really sensitive to where the file is and I would suggest always placing it in the actual app home directory and not elsewhere.

Since we spawn an external process that sends a message we don't really know what went wrong as there is no error responses from the process in some OS's.

Shai Almog
  • 51,749
  • 5
  • 35
  • 65
  • This is on Android, so the file is in the actual app home directory. I should mention that I'm not sure if the parameter should just be the path to the file. The parameter is declared to be a String, but it's called fileUri rather than pathToFile. Does it need a protocol? Here's a sample path: /data/data/com.mycompany.myapp/files/snapshot-May-17--2016-2.59.13.13-AM.png I did this about a month ago and it worked fine. – MiguelMunoz May 17 '16 at 10:06
  • It should be in the path returned from getAppHome. The reason for this is that the mail app can't physically see your files due to security restrictions. So we automatically detect this special case of a file being in the app home and transfer the file to a common location. – Shai Almog May 18 '16 at 03:36
  • It is on the path returned from getAppHomePath(). Are you sure this still works on Android? It was working for me last month, and now it's not working anymore. I'm not doing anything different. – MiguelMunoz May 18 '16 at 06:42
  • Did you update your Android OS in the interim? If you connect a cable and DDMS do you see an exception? – Shai Almog May 19 '16 at 06:41
  • I did run the regular System Update since I did this. Should that make a difference? As for DDMS, I haven't been able to figure out how to launch it. (The instructions say to click the "DDMS Menu Button" in Android Studio, but I can't find one.) However, I log Throwables and have looked using ADB, and I can say for certain that my code to attach a file and send an email is not throwing anything. If you still want to know what DDMS says, let me know and I'll give it another look. – MiguelMunoz May 19 '16 at 09:12
  • It's possible that something changed with a minor OS version. We just ran it and it seems to work fine on our system so maybe its something specific to your device. There is a deprecated tool that still works well called ddms in the android SDK. Just run it and connect the device, you can then select the device in the menu and you will see it's logs. – Shai Almog May 20 '16 at 03:45
  • I have the latest Android Studio installed, and I've followed the instructions for launching ddms, but there's no ddms button. In the graphic on their instructions web page, There's a top pane and a bottom pane. My Android Monitor only has the bottom pane, with two tabs: logcat and monitor. I can't find ddms in settings either. Are you using an older version of Android Studio? Is there something I need to turn on? – MiguelMunoz May 23 '16 at 05:25
  • Let me ask my question again. I know, using try/catch, that no exceptions are being thrown within reach of my code. Is that why you're asking me to use ddms? Or are there other internal exceptions that you want me to look for? – MiguelMunoz May 24 '16 at 02:30
  • The code is implemented asynchronously since we need to do everything in the Android thread so a thrown exception there will not propagate to your code. We do try to catch such exceptions but anything can happen. There is a physical `ddms` command in the tools directory of the command line SDK. You don't need to have Android studio for that. – Shai Almog May 24 '16 at 03:35
  • Thank you. I added a stack trace to the original spec. – MiguelMunoz May 25 '16 at 10:30
  • This looks related to this Android bug: http://stackoverflow.com/questions/15776416/java-lang-classcastexception-android-text-spannablestringbuilder-cannot-be-cast are you using HTML or plain text emails? – Shai Almog May 26 '16 at 16:43
  • Plain text emails. – MiguelMunoz May 26 '16 at 18:52
  • I'm specifying plain text, but when I look at the headers for the emails I received, it says "text/html". – MiguelMunoz May 26 '16 at 19:12
  • I'm glad you asked, because I realized I was calling setMimeType("image/png") when I should have been calling setAttachmentMimeType("image/png"). But fixing this didn't help. I just changed it to setMimeType("text/plain") but the email header tells me it's "text/html". I should say that the API could be cleaner. Having one method for adding a single attachment and another for adding multiple attachments is error prone. A better API would be addAttachment(String filePath, String mimeType), which would add both to the email map, instead of building the map after an attachment has been added. – MiguelMunoz May 26 '16 at 20:30
  • We initially only added one item and this was changed after the fact to remain compatible with some edge behaviors of a single attachment API. Try using MIME_TEXT for the mime type and see if this works. – Shai Almog May 27 '16 at 04:10
  • I've added an issue to include the suggested workaround into the Android port https://github.com/codenameone/CodenameOne/issues/1782 – Shai Almog May 28 '16 at 03:53
  • Thank you. I appreciate that. – MiguelMunoz May 28 '16 at 21:47