用java实现邮件发送时运行代码报错提示 无效的协议为 null
报错信息如下
javax.mail.NoSuchProviderException:Invalid protocol:null
出错处源代码
Transport transport = session.getTransport();
ctrl+鼠标左键进入源码查看,源码为:
/**
* Get a Transport object that implements this user's desired
* Transport protcol. The <code>mail.transport.protocol</code> property
* specifies the desired protocol. If an appropriate Transport
* object cannot be obtained, MessagingException is thrown.
*
* @return a Transport object
* @exception NoSuchProviderException If the provider is not found.
*/
public Transport getTransport() throws NoSuchProviderException {
return getTransport(getProperty("mail.transport.protocol"));
}
发现,源码是从Properties中取了mail.transport.protocol的值
再进入getProperty的源码查看,源码如下
/**
* Returns the value of the specified property. Returns null
* if this property does not exist.
*
* @return String that is the property value
*/
public String getProperty(String name) {
return props.getProperty(name);
}
再进入props.getProperty的源码查看,源码如下
/**
* Searches for the property with the specified key in this property list.
* If the key is not found in this property list, the default property list,
* and its defaults, recursively, are then checked. The method returns
* {@code null} if the property is not found.
*
* @param key the property key.
* @return the value in this property list with the specified key value.
* @see #setProperty
* @see #defaults
*/
public String getProperty(String key) {
Object oval = super.get(key);
String sval = (oval instanceof String) ? (String)oval : null;
return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
}
发现其实就是相当于一个键值对,在通过key的值去取出value的值,也就是通过mail.transport.protocol取出对应的值
这里通过调试发现
发现我们所需要的value值对应的key是mail.transport,所以底层源码找不到对应的value值,这里把它改过来
更改前代码:
Properties properties = new Properties();
properties.setProperty("mail.host", host);
properties.setProperty("mail.transport", "smtp"); // 更改处
properties.setProperty("mail.smtp.auth", "true");
更改后代码:
Properties properties = new Properties();
properties.setProperty("mail.host", host);
properties.setProperty("mail.transport.protocol", "smtp"); // 更改处
properties.setProperty("mail.smtp.auth", "true");
之后成功解决问题
关于这个问题博主在查阅他人的博客时,注意到这样一个解决方案:
将代码:
Transport transport = session.getTransport();
改为:
Transport transport = session.getTransport("smtp");
博主这里也查看了源码,源码如下:
/**
* Get a Transport object that implements the specified protocol.
* If an appropriate Transport object cannot be obtained, null is
* returned.
*
* @return a Transport object
* @exception NoSuchProviderException If provider for the given
* protocol is not found.
*/
public Transport getTransport(String protocol) throws NoSuchProviderException {
return getTransport(new URLName(protocol, null, -1, null, null, null));
}
其中getTransport源码为:
/**
* Get a Transport object for the given URLName. If the requested
* Transport object cannot be obtained, NoSuchProviderException is thrown.
*
* The "scheme" part of the URL string (Refer RFC 1738) is used
* to locate the Transport protocol. <p>
*
* @param url URLName that represents the desired Transport
* @return a closed Transport object
* @see javax.mail.URLName
* @exception NoSuchProviderException If a provider for the given
* URLName is not found.
*/
public Transport getTransport(URLName url) throws NoSuchProviderException {
String protocol = url.getProtocol();
Provider p = getProvider(protocol);
return getTransport(p, url);
}
关于这个方法,博主对此的理解是相当于重新创建了一个属性,那么我们之前事先设置好的属性就等于白设置了,所以博主最后没有使用这个方法,如果大家是跟我一样事先设置好Properties的属性的话,博主个人还是建议使用上面的方法,这里就看大家各自的代码是如何编写实现的了
有理解不到位或是不足之处欢迎在评论区指出讨论