title: Calling Linux's "mailx" through java code: message-text always goes into attachment
body: <p>Since my SMTP provider has limit on number of emails that can be sent in  a day, I wrote a Java code to call the "mailx" of Linux system, my java-program is running on.</p>
  
  <p>Here is that code:</p>
  
  <pre><code>package sys.cmd;
  
  import java.io.ByteArrayInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.util.ArrayList;
  import java.util.List;
  
  public class IntermediateJavaLinuxMailX {
  
      public static void main(String[]args) throws IOException{
          email(
                  new ArrayList&lt;String&gt;(){{
                      add("myemailid@myserver.com");
                      add("myothermailid@otherserver.com");
                  }},
                  "Error Message",
                  "Hello World!\r\n This is message"
          );
      }
  
      public static void email(
              List&lt;String&gt;toEmailIds,
              String subject,
              String msgText
              ) throws IOException{
          String toEmails = toString(toEmailIds);
          String[]args=new String[]{"/bin/sh" , "-c", "mailx -s \""+subject+"\" "+toEmails};
          System.out.println("The command for bash is: "+args[2]);
          Process proc= Runtime.getRuntime().exec(args);
          OutputStream o = proc.getOutputStream();//probable output for text
          InputStream i = new ByteArrayInputStream(msgText.getBytes());//probable input for message-text
          read2end(i, o);
          o.close();
      }
  
      private static String toString(List&lt;String&gt; toEmailIds) {
          StringBuilder sb= new StringBuilder();
          for(String toEmailId:toEmailIds){
              sb.append(toEmailId).append(' ');
          }
          return sb.toString();
      }
  
      private static void read2end(InputStream i, OutputStream o) throws IOException {
          byte[]b=new byte[1000];
          for(int a=0;(a=i.read(b))&gt;-1;)
              o.write(b, 0, a);
          i.close();
      }
  
  }
  </code></pre>
  
  <p>The problem is: The email received on the recipients side, the text is not in the message-body, but it is in an attachment-file named "noname".</p>
  
  <p>The question is: How can I make the string in <code>msgText</code> appear in email's message-body.</p>
  
  <hr>
  
  <p>Adding one more thing I did so far:</p>
  
  <hr>
  
  <p>I wrote another code, that uses temporary files for storing message-text &amp; then uses file-redirection (<code>&lt;</code>) for adding message-text &amp; it gives desired result. But that is an indirect way. Is there any direct-way? Here is that another code:</p>
  
  <pre><code>    public static void email(
              List&lt;String&gt;toEmailIds,
              List&lt;String&gt;ccEmailIds,
              List&lt;String&gt;bccEmailIds,
              String subject,
              byte[][]attachContents,
              String messageText
              ) throws IOException{
          String toEmails=toString(" " , toEmailIds,' ');
          String ccEmails=notEmpty(ccEmailIds)?toString(" -c ", ccEmailIds,','):"";
          String bcEmails=notEmpty(bccEmailIds)?toString(" -b ", bccEmailIds,','):"";
          String recip=bcEmails+ccEmails+toEmails;
          String[]attachmentTempFiles=new String[notEmpty(attachContents)?attachContents.length:0];
          String attachFilePaths="";
          for(int x = 0;x&lt;attachmentTempFiles.length;++x){
              String attachTempPath = "/path/temp/attach_"+x+".file";
              byteArray2File(attachContents[x],attachTempPath);
              attachmentTempFiles[x]=" -a "+attachTempPath;
              attachFilePaths+=attachmentTempFiles[x];
          }
          String msgTxtTempFilePath="/path/temp/msg.txt";
          byteArray2File(messageText.getBytes(), msgTxtTempFilePath);
          msgTxtTempFilePath=" &lt; "+msgTxtTempFilePath;
          String mailxCommand = "mailx " + attachFilePaths + " -s \"" + subject +"\" "+ recip + msgTxtTempFilePath;
          Runtime.getRuntime().exec(new String[]{"/bin/sh" , "-c", mailxCommand});
      }
  
      private static void byteArray2File(byte[] bs, String path) throws IOException {
          FileOutputStream fos=new FileOutputStream(path);
          ByteArrayInputStream bais=new ByteArrayInputStream(bs);
          read2end(bais, fos);
          fos.close();
      }
  
      private static boolean notEmpty(byte[][] bs) {
          return bs!=null &amp;&amp; bs.length&gt;0;
      }
  
      private static boolean notEmpty(List&lt;String&gt; strings) {
          return strings!=null &amp;&amp; !strings.isEmpty();
      }
  
      private static String toString(String pre, List&lt;String&gt; toEmailIds,char separator) {
          StringBuilder sb= new StringBuilder(pre);
          for(String toEmailId:toEmailIds){
              sb.append(toEmailId).append(separator);
          }
          return sb.substring(0,sb.length()-1);
      }
  
      private static void read2end(InputStream i, OutputStream o) throws IOException {
          byte[]b=new byte[1000];
          for(int a=0;(a=i.read(b))&gt;-1;)
              o.write(b, 0, a);
          i.close();
      }
  </code></pre>
  
  <hr>
  
  <p><b>
  --Edit-- Added after @Serge Ballesta's comment:
  </b></p>
  
  <p>"Hmm, I tried googling around and found Plain text file pipelined to Linux mailx turns to "Content-Type: application/octet-stream" (an attachment). Could your problem be the same ? To be sure could you control the headers of the received messages ?"</p>
  
  <hr>
  
  <p>This code too had same effect:</p>
  
  <pre><code>        email(
                  new ArrayList&lt;String&gt;(){{add("user_abc@mail1.com");add("person-xyz@mailer2.com");}},
                  "Error Message",
                  "Content-Type: text/plain; charset=us-ascii\r\n" +
                  "Content-Disposition: inline\r\n\r\n" +
                  "Hello World!\r\n" +
                  "This is message.\r\n\r\n\r\n"
          );
  </code></pre>
  
  <p>Still, all the message text goes into an attachment named "noname".</p>