Java Runtime.exec()不从命令行发送电子邮件

时间:2014-07-10 15:39:35

标签: java linux macos

我正在创建一个java应用程序,我想添加的功能之一是向用户发送生成的电子邮件。我在Macbook上设置了邮件,我可以从命令行发送电子邮件。我在调用runtime.exec()时发送电子邮件时遇到问题。任何人都知道它为什么不执行和发送电子邮件?

Runtime runtime = Runtime.getRuntime();

try {
    runtime.exec("echo This is the body | mail -s Subject -F myemail@gmail.com");
}
catch ( Exception e ) {

    // TODO Auto-generated catch block
    e.printStackTrace();
}

我没有得到任何错误,一切都编译得很好。我只是没有收到任何电子邮件。如果有人能够帮助,我将非常感谢。

3 个答案:

答案 0 :(得分:6)

Runtime.exec(String)不会通过将整个字符串粘贴到UNIX shell并运行它来执行它。这是因为它是一个巨大的安全漏洞。

想象一下你这样做了:

runtime.exec("Hello "+name+" | mail ...");

然后,我可以将name设置为; rm -rf /*; echo&& cat /etc/passwd,或其他一些shell注入代码。

所以,Java is breaking up your command into parts

  

更准确地说,命令字符串使用由调用new StringTokenizer(命令)创建的StringTokenizer分解为标记,而不进一步修改字符类别。然后,由tokenizer生成的标记以相同的顺序放置在新的字符串数组cmdarray中。

最终,您只使用echo|等参数运行mail命令。 echo命令只会将这些输出打印到您不收集的标准输出。它永远不会调用mail命令。

由于涉及安全风险,您不应使用mail命令从Java发送邮件。您应该使用JavaMail包,它提供了一个安全方便的API来发送邮件。 UNIX mail命令通过连接到端口25上本地计算机上运行的sendmail守护程序来工作,JavaMail也可以这样做。

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;

public class SendMail {
    public static sendMail(String from, String to, String subject, String body)
        throws MessagingException
    {
        final Properties p = new Properties();
        p.put("mail.smtp.host", "localhost");
        final Message msg = new MimeMessage(Session.getDefaultInstance(p));
        msg.setFrom(new InternetAddress(from));
        msg.addRecipient(RecipientType.TO, new InternetAddress(to));
        msg.setSubject(subject);
        msg.setText(body);
        Transport.send(msg);
    }
}

答案 1 :(得分:3)

为什么不使用JavaMail

使用示例:

private boolean sendMail(String host, String port, String user, String password,  List<String> toList, String htmlBody, String subject) {
    Properties props = System.getProperties();
    props.put("mail.smtp.user", user);
    props.put("mail.smtp.password", password);
    props.put("mail.smtp.host", host);
    props.put("mail.smtp.port", port);
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.smtp.EnableSSL.enable", "true");

    Session session = Session.getInstance(props, null);

    MimeMessage message = new MimeMessage(session);
    try {

        message.setFrom(new InternetAddress(user));

        // To get the array of addresses
        for (String to : toList) {
            message.addRecipient(Message.RecipientType.TO,
                    new InternetAddress(to));
        }

        message.setSubject(subject);
        message.setContent(htmlBody, "text/html");

        Transport transport = session.getTransport("smtp");
        try {
            transport.connect(host, user, password);
            transport.sendMessage(message, message.getAllRecipients());
        } finally {
            transport.close();
        }

    } catch (Exception e) {
        return false;
    } 
    return true;
}

答案 2 :(得分:1)

因为你没有产生shell和|是一个shell功能。一个有效的例子:

创建一个shell脚本并将命令数组传递给exec()。

class Test {
  public static void main(String[] args) {
    try {
      Runtime runtime = Runtime.getRuntime();
      String[] cmd = { "sh", "send.sh", "This is the body", "Subject", "myemail@gmail.com"};
      runtime.exec(cmd);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

Shell脚本:

echo $1 | mail -s $2 -F $3