使用JAVA通过Gmail SMTP服务器发送电子邮件

16

这段代码有什么问题?不知何故,它在Transport.send(message);这一行进入了一个无限循环,没有错误消息,也没有异常,只是可能会无限循环(我不知道,因为我没有等待超过5-10分钟)。

final String username = "<mail_name>";
final String password = "<password>";

Properties props = new Properties();
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.host", "smtp.gmail.com");
props.put("mail.smtp.port", "465");

Session session = Session.getInstance(props,
        new javax.mail.Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        });

try {

    Message message = new MimeMessage(session);
    message.setFrom(new InternetAddress("<mail_from>@gmail.com"));
    message.setRecipients(Message.RecipientType.TO,
            InternetAddress.parse("<mail_to>@gmail.com"));
    message.setSubject("Test Subject");
    message.setText("Test");

    Transport.send(message);

    System.out.println("Done");

} catch (MessagingException e) {
    throw new RuntimeException(e);
}

我建议在 MessagingException 后添加 catch (Exception e){},以查看是否抛出了其他类型的异常。还应该添加一个 finally 块。您还可以添加 log4j.xml 并将 javax.mail 类设置为 DEBUG,以查看可能发生的其他情况。 - Bizmarck
好提示,谢谢!将会测试它。 - czupe
不幸的是,仍然在Transport.send(message)这一行等待... 有人能验证这段代码的正确性吗? - czupe
4个回答

20

这里我提供了一些对我有效的更改:

Session session = Session.getInstance(props,null);
您可以像之前一样实例化消息对象。最后,执行以下操作:
Transport transport = session.getTransport("smtp");
String mfrom = "yourGmailUsernameWithout@"// example laabidiraissi 
transport.connect("smtp.gmail.com", mfrom, "thepassword");
transport.sendMessage(message, message.getAllRecipients());

编辑,你能否帮我一个忙,复制/粘贴并尝试运行这个例子,展示它是如何显示的:

package com.test;

import java.util.Properties;

import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;

import org.junit.Test;

public class EmailService {

@Test
public void test(){
    Properties props = System.getProperties();
    props.put("mail.smtp.starttls.enable", true); // added this line
    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.user", "username");
    props.put("mail.smtp.password", "password");
    props.put("mail.smtp.port", "587");
    props.put("mail.smtp.auth", true);



    Session session = Session.getInstance(props,null);
    MimeMessage message = new MimeMessage(session);

    System.out.println("Port: "+session.getProperty("mail.smtp.port"));

    // Create the email addresses involved
    try {
        InternetAddress from = new InternetAddress("username");
        message.setSubject("Yes we can");
        message.setFrom(from);
        message.addRecipients(Message.RecipientType.TO, InternetAddress.parse("receivermail"));

        // Create a multi-part to combine the parts
        Multipart multipart = new MimeMultipart("alternative");

        // Create your text message part
        BodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setText("some text to send");

        // Add the text part to the multipart
        multipart.addBodyPart(messageBodyPart);

        // Create the html part
        messageBodyPart = new MimeBodyPart();
        String htmlMessage = "Our html text";
        messageBodyPart.setContent(htmlMessage, "text/html");


        // Add html part to multi part
        multipart.addBodyPart(messageBodyPart);

        // Associate multi-part with message
        message.setContent(multipart);

        // Send message
        Transport transport = session.getTransport("smtp");
        transport.connect("smtp.gmail.com", "username", "password");
        System.out.println("Transport: "+transport.toString());
        transport.sendMessage(message, message.getAllRecipients());


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

如果尝试使用25或587端口不起作用,无论如何检查您的解决方案...主线程中的异常:"java.lang.RuntimeException: javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 25; nested exception is: java.net.ConnectException: Connection refused: connect" - czupe
好消息终于来了,我们得到了一些异常。你的异常很经典:https://dev59.com/9Ww05IYBdhLWcg3wkirX - Laabidi Raissi
你检查了防火墙吗?587端口是否也出现了相同的异常? - Laabidi Raissi
请帮我一个忙,复制/粘贴并尝试运行这个例子,展示它的输出结果(请参见编辑后的答案)。 - Laabidi Raissi
看起来它正在工作,但没有时间深入了解两个代码的区别,很奇怪,无论如何感谢你的固执:) 如果我能完全理解它就好了... 我会花时间去学习它:) - czupe
显示剩余11条评论

3

好的,这比我第一次想象的要复杂一些...总结一下我的理解:

  • There is a very useful command: session.setDebug(true);. If you set this true, every important process will be debuged to the console. I recommend to use it.
  • The second computer could only work with the secure option, you can switch this one with: Transport transport = session.getTransport("smtps"); rather of the non secure smtp... The JavaMail API Transport object will also take care of the ports (respectively smtp: 587, smtps: 465)
  • You can use also the static method of the Transport class for sending the message and (saving it before, non static sendMessage method will not save the message), but this time you need to use the javax.mail.Authenticator at the session creation, like this:

    Session session = Session.getInstance(props,         new javax.mail.Authenticator() {
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication("login", "password");
        }
    

    });

1.4.2版本的JavaMailApi针对此问题有另一个异常...如果不使用它,您将无法通过静态方法进行身份验证。如果使用实例方法,则可以。

  • 一台计算机具有maven并获取了JavaMail API 1.4.2版本。第二台计算机具有已下载的库,带有1.4.7版本,我想这也会影响事情
  • 第一台计算机使用Netbeans,第二台计算机使用Intellij... +1) 互联网上有很多旧的和糟糕的示例代码,这使得正确使用此API更加困难。

所以非常混乱,但还是有一些基本概念需要关注...


1
我可以重现您问题中描述的行为并加以修复。 在send方法处出现了卡顿。
SMTPTransport(Service).connect(String, int, String, String) line: 308   

连接不成功是因为您使用了错误的端口连接gmail smtp主机:465 请将其更改为587
props.put("mail.smtp.port", "587");

并且它会正常工作。


是啊,不知道为什么我选择了465端口,但无论如何它仍然无法工作 : ( - czupe
你现在遇到了什么异常或错误?你的java.exe是否被防火墙允许通过? - A4L
这个错误信息是:java.lang.RuntimeException: javax.mail.MessagingException: Could not connect to SMTP host: smtp.gmail.com, port: 25; nested exception is: java.net.ConnectException: Connection refused: connect。我已经关闭了整个Windows防火墙。 - czupe
似乎您的应用程序不支持SSL。smtp.gmail.com需要安全连接,否则您将不得不选择另一个主机,请参见Google支持页面。您可能需要明确指定它,通过获取支持安全协议smtpsTransport实例,并使用它来发送您的消息。请参考此问题的已接受答案 - A4L

1
使用Simple Java Mail应该很简单:
Email email = new Email();

email.setFromAddress("lollypop", "lol.pop@somemail.com");
email.addRecipient("C.Cane", "candycane@candyshop.org", RecipientType.TO);
email.setText("We should meet up!");
email.setTextHTML("<b>We should meet up!</b>");
email.setSubject("hey");

new Mailer("smtp.gmail.com", 25, "your user", "your password", TransportStrategy.SMTP_TLS).sendMail(email);
new Mailer("smtp.gmail.com", 587, "your user", "your password", TransportStrategy.SMTP_TLS).sendMail(email);
new Mailer("smtp.gmail.com", 465, "your user", "your password", TransportStrategy.SMTP_SSL).sendMail(email);

如果您开启了双重身份验证登录,您需要从您的Google帐户生成一个应用程序特定密码

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接