我正在运行一个非常基本的Javamail程序来尝试发送电子邮件。这是带有main()的独立程序。一旦我让它工作,我计划在tomcat下运行的servlet中使用Javamail。
运行此程序时,我收到身份验证登录失败错误。我尝试了几种不同的属性设置,但都没有解决问题。
然后我在SO上找到一篇帖子,建议降低我谷歌账户的安全级别。当我降低安全设置时,身份验证成功。
当然,我立即回到了谷歌账户的更高安全级别。
我的问题是,如何让我的应用程序更安全,这样gmail就不会拒绝身份验证?
程序代码如下所示。该程序与SO上许多其他Javamail问题中的代码非常相似。
TryJavamail.java
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;
public class TryJavamail {
public static void main(String args[]) throws MessagingException {
String submitName = "John Doe";
String submitEmail = "from@example.com";
String submitMessage = "This is the message";
Properties props = new Properties();
props.put("mail.transport.protocol", "smtp");
props.setProperty("mail.smtp.host", "smtp.gmail.com");
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.smtp.ssl.enable", "true");
props.setProperty("mail.smtp.port", "465");
Session session = Session.getInstance(props, null);
session.setDebug(true);
Message message = new MimeMessage(session);
message.setSubject("Message from myapp website submit");
message.setText(submitName + "; " + submitMessage);
Address toAddress = new InternetAddress(submitEmail);
message.setRecipient(Message.RecipientType.TO, toAddress);
Transport transport = session.getTransport("smtp");
transport.connect("smtp.gmail.com", "---userid---", "---password---");
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
}
如何使我的应用程序更安全,以便gmail不会拒绝身份验证?
在我看来,一个好方法是启用双向身份验证,并在代码中用生成的特定于应用程序的密码替换正常的Gmail密码。
final String smtpServer = "smtp.gmail.com";
final String userAccount = "****@gmail.com"; // Sender Account.
final String password = "****"; // Password -> Application Specific Password.
final String SOCKET_FACTORY = "javax.net.ssl.SSLSocketFactory";
final String smtpPort = "587";
final String PORT = "465";
final Properties props = new Properties();
props.put("mail.smtp.host", smtpServer);
props.put("mail.smtp.user", userAccount);
props.put("mail.smtp.password", password);
props.put("mail.smtp.port", smtpPort);
props.put("mail.smtp.auth", true);
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.debug", "false");
props.put("mail.smtp.socketFactory.port", PORT);
props.put("mail.smtp.socketFactory.class", SOCKET_FACTORY);
props.put("mail.smtp.socketFactory.fallback", "false");
Session session = Session.getInstance(props,
new javax.mail.Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(userAccount, password);
}
});
MimeMessage mimeMessage = new MimeMessage(session);
final Address toAddress = new InternetAddress("****@outlook.com"); // toAddress
final Address fromAddress = new InternetAddress(userAccount);
mimeMessage.setContent("This is a test mail...", "text/html; charset=UTF-8");
mimeMessage.setFrom(fromAddress);
mimeMessage.setRecipient(javax.mail.Message.RecipientType.TO, toAddress);
mimeMessage.setSubject("Test Mail...");
Transport transport = session.getTransport("smtp");
transport.connect(smtpServer, userAccount, password);
transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
我将我的解决方案作为一个单独的答案。我之前编辑过这个问题,将其包括在内,但问题太长了。
下面显示的是一个servlet,它使用OAuth2从我的网站上的“联系人”表单发送电子邮件。我按照比尔回答的链接中提供的说明进行操作。
SendMessage.java(需要更复杂的实现,请阅读代码中的注释)
/*
* This program is adapted from sample code provided
* by Google Inc at the following location:
* https://github.com/google/gmail-oauth2-tools
*
*/
package com.somedomain.servlet;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Properties;
import java.util.logging.Logger;
import javax.mail.Session;
import javax.mail.Message;
import javax.mail.Address;
import javax.mail.Transport;
import javax.mail.URLName;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.InternetAddress;
import java.security.Provider;
import java.security.Security;
import com.sun.mail.smtp.SMTPTransport;
import com.somedomain.oauth2.AccessTokenFromRefreshToken;
import com.somedomain.oauth2.OAuth2SaslClientFactory;
public class SendMessage extends HttpServlet {
private static final Logger logger =
Logger.getLogger(SendMessage.class.getName());
public static final class OAuth2Provider extends Provider {
private static final long serialVersionUIS = 1L;
public OAuth2Provider() {
super("Google OAuth2 Provider", 1.0,
"Provides the XOAUTH2 SASL Mechanism");
put("SaslClientFactory.XOAUTH2",
"com.somedomain.oauth2.OAuth2SaslClientFactory");
}
}
public static void initialize() {
Security.addProvider(new OAuth2Provider());
}
public static SMTPTransport connectToSmtp(Session session,
String host,
int port,
String userEmail,
String oauthToken,
boolean debug) throws Exception {
final URLName unusedUrlName = null;
SMTPTransport transport = new SMTPTransport(session, unusedUrlName);
// If the password is non-null, SMTP tries to do AUTH LOGIN.
final String emptyPassword = "";
transport.connect(host, port, userEmail, emptyPassword);
return transport;
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
String submitName = request.getParameter("name");
String submitEmail = request.getParameter("email");
String submitPhone = request.getParameter("phone");
String submitMessage = request.getParameter("message");
try {
String host = "smtp.gmail.com";
int port = 587;
String userEmail = "---email account used for oauth2---";
String appEmail = "---email account for receiving app emails---";
String oauthToken = "";
initialize();
//
// Gmail access tokens are valid for 1 hour. A more sophisticated
// implementation would store access token somewhere and reuse it
// if it was not expired. A new access token should be generated
// only if html" target="_blank">access token is expired. Abandoning unexpired access
// tokens seems wasteful.
//
oauthToken = AccessTokenFromRefreshToken.getAccessToken();
Properties props = new Properties();
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.starttls.required", "true");
props.put("mail.smtp.sasl.enable", "true");
props.put("mail.smtp.sasl.mechanisms", "XOAUTH2");
props.put(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oauthToken);
Session session = Session.getInstance(props);
session.setDebug(true);
SMTPTransport smtpTransport = connectToSmtp(session, host, port,
userEmail, oauthToken, true);
Message message = new MimeMessage(session);
message.setSubject("Submit from somedomain.com website");
message.setText("Name=" + submitName + "\n\nEmail=" + submitEmail +
"\n\nPhone=" + submitPhone + "\n\nMessage=" + submitMessage);
Address toAddress = new InternetAddress(appEmail);
message.setRecipient(Message.RecipientType.TO, toAddress);
smtpTransport.sendMessage(message, message.getAllRecipients());
smtpTransport.close();
} catch (MessagingException e) {
System.out.println("Messaging Exception");
System.out.println("Error: " + e.getMessage());
} catch (Exception e) {
System.out.println("Messaging Exception");
System.out.println("Error: " + e.getMessage());
}
String url = "/thankyou.html";
response.sendRedirect(request.getContextPath() + url);
}
}
oken.java
/*
* For OAuth2 authentication, this program generates
* access token from a previously acquired refresh token.
*/
package com.somedomain.oauth2;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import java.util.LinkedHashMap;
import java.io.DataOutputStream;
import java.io.Reader;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
public class AccessTokenFromRefreshToken {
public static String getAccessToken() {
HttpURLConnection conn = null;
String accessToken = null;
try {
URL url = new URL("https://accounts.google.com/o/oauth2/token");
Map<String,Object> params = new LinkedHashMap<>();
params.put("client_id", "***********.apps.googleusercontent.com");
params.put("client_secret", "****************");
params.put("refresh_token", "*****************");
params.put("grant_type", "refresh_token");
StringBuilder postData = new StringBuilder();
for (Map.Entry<String,Object> param : params.entrySet()) {
if (postData.length() != 0) postData.append('&');
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length",
String.valueOf(postDataBytes.length));
conn.setRequestProperty("Content-language", "en-US");
conn.setDoOutput(true);
DataOutputStream wr = new DataOutputStream (
conn.getOutputStream());
wr.write(postDataBytes);
wr.close();
StringBuilder sb = new StringBuilder();
Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
for ( int c = in.read(); c != -1; c = in.read() ) {
sb.append((char)c);
}
String respString = sb.toString();
// Read access token from json response
ObjectMapper mapper = new ObjectMapper();
AccessTokenObject accessTokenObj = mapper.readValue(respString,
AccessTokenObject.class);
accessToken = accessTokenObj.getAccessToken();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(conn != null) {
conn.disconnect();
}
}
return(accessToken);
}
}
AccessTokenObject。Java语言
/*
* Class that corresponds to the JSON
* returned by google OAuth2 token generator
*/
package com.somedomain.oauth2;
import com.fasterxml.jackson.annotation.JsonProperty;
public class AccessTokenObject {
@JsonProperty("access_token")
private String accessToken;
@JsonProperty("token_type")
private String tokenType;
@JsonProperty("expires_in")
private int expiresIn;
public String getAccessToken() { return accessToken; }
public String getTokenType() { return tokenType; }
public int getExpiresIn() { return expiresIn; }
public void setAccessToken(String accessToken) { this.accessToken = accessToken; }
public void setTokenType(String tokenType) { this.tokenType = tokenType; }
public void setExpiresIn(int expiresIn) { this.expiresIn = expiresIn; }
}
OAuth2SaslClient。java—使用的代码与gmail-oauth2-tools中的代码相同,只是在顶部添加了一个package语句(package com.somedomain.oauth2;)
OAuth2SaslClientFactory。java-未更改使用的代码,添加了package语句
您可能想使用OAuth2身份验证。
我写了一个从java(javamail/jaf)发送简单邮件的代码。运行该程序后,我收到一封来自google的电子邮件,表明我的帐户正被不安全的设备/应用程序访问。然后我不得不更改我的gmail帐户的设置以允许登录“不太安全的应用程序”选项。然后我收到了来自程序的电子邮件。 我需要在不更改选项的情况下发送电子邮件,允许在我的帐户中使用“不太安全的应用程序”选项。请帮忙。 我的代码是:
null 我正在尝试使用这个共享对话框在我自己的设备与我自己的Facebook帐户,这是应用程序的管理员以及。 在我的项目中: 项目名称:abddef app_name:Abd Def(在android manifest中)
我正在编写一个简单的java程序,可以检查我的gmail收件箱。我在http://www.tutorialspoint.com/javamail_api/javamail_api_checking_emails.html.但是当我试着运行这个程序时 我得到以下错误 但是当我在我的gmail帐户中启用“访问不太安全的应用程序”时,这将完美运行。我如何解决这个问题。这个问题类似于只有当帐户启用了“访问
问题内容: 我一直在做很多研究,找不到解决这个问题的方法。我正在尝试执行从https服务器到运行带有自定义自签名证书的码头的locahosthttps服务器的jQueryajax调用。我的问题是我无法确定响应是连接被拒绝还是响应不安全(由于缺少证书接受)。有没有办法确定两种情况之间的差异?的,并且总是在这两种情况下是相同的,即使在Chrome控制台我可以看到一个区别: 对于这两种情况,始终为“”,
我正在尝试制作一种电子邮件客户端程序。我正在使用传输。connect尝试使用用户的用户名和密码连接到用户的Gmail帐户,但如果他们没有启用较不安全访问的设置,应用程序将返回此信息,我不希望必须这样做,因为不是每个用户都知道。我也不需要获取或发送邮件,我只需要获得有效的登录。
我正在尝试使用Java向Gmail帐户发送邮件,代码如下。我似乎做的每件事都是正确的,但我收到了身份验证失败的消息。谷歌想让我打开“不太安全的应用”功能来实现传输。 有没有一种方法可以让Gmail对Java满意,并且不会出现“打开不太安全的应用程序”的错误? 错误: 代码: 我已经做了研究,所以据我所知,代码不是问题所在,只是没有看到一个解决方案,用于不太安全的应用程序消息。 参考文献: 参考文献