【问题标题】:Java Runtime.exec() not sending emails as from the command lineJava Runtime.exec() 不从命令行发送电子邮件
【发布时间】:2014-07-10 15:39:34
【问题描述】:

我正在创建一个 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();
}

我没有收到任何错误,一切编译正常。我只是没有收到任何电子邮件发送出去。如果有人能帮忙,将不胜感激。

【问题讨论】:

  • 尝试调用Process proc = runtime.exec(...);proc.waitFor()...,然后从进程中打印出流,看看有没有错误。 Process
  • Runtime.exec not working的可能重复

标签: java linux macos


【解决方案1】:

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(command) 创建的 StringTokenizer 分解为标记,无需进一步修改字符类别。然后将分词器生成的令牌以相同的顺序放置在新的字符串数组 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);
    }
}

【讨论】:

  • 我正在尝试向我连接到的 Intranet 上的用户帐户发送电子邮件。我知道这只是向本地主机上的用户发送电子邮件。是否需要进行任何配置或仅修改 p.put() 方法调用?
  • 如果您还没有这样做,您可以打开 Mac OS X 的本地 SMTP 服务器,如this answer 中所述。本地 MTA 意味着任何本地程序都可以连接并请求发送邮件,无论是针对本地用户还是远程用户。
【解决方案2】:

为什么不使用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;
}

【讨论】:

  • 由于合规性,当我无法在我的代码或任何配置文件中使用用户名/密码时,这将不起作用。安全团队正在敦促在正在运行的 Unix 系统上使用 mailx,但通过 Runtime 执行的工作没有按预期工作。
【解决方案3】:

因为您没有生成 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

【讨论】:

  • 这不起作用。我希望它确实是因为我在设置 JavaMail 时遇到了麻烦,哈哈
  • :)。哦,我在我的 Linux 笔记本电脑上对其进行了测试。也许您的外壳被称为不同,我从谷歌搜索得知它是 bash。还要确保将脚本与类文件放在同一目录中,或在 send.sh 前面添加完整路径
  • 正是我想要的。谢谢@ArnaudKleinveld。上面的答案没有考虑这样一个事实,即如果企业界阻塞了端口 25 和 487,而您只能通过 mail 命令发送邮件,那么上述解决方案将根本不起作用。但这会奏效。
猜你喜欢
  • 2023-03-10
  • 2010-09-20
  • 2010-09-07
  • 2015-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-16
  • 2011-10-13
相关资源
最近更新 更多