我需要通过(外部)SMTP服务器从Java发送电子邮件,但此服务器只接受CRAM-MD5身份验证,JavaMail不支持。
将这些电子邮件发送给您的好方法是什么? (它必须是Java。)
答案 0 :(得分:6)
以下是thread,表示您需要添加以下属性:
props.put("mail.smtp.auth.mechanisms", "CRAM-MD5")
同样在Geronimo实现中,有CramMD5Authenticator
希望有助于解决这个老问题。
答案 1 :(得分:4)
这对您没有直接帮助,但是,如果将Java SASL documentation布尔属性设置为{{1},则JavaMail中的IMAP连接会支持SASL(因此CRAM-MD5,请参阅mail.imap.sasl.enable
) }}
不幸的是,没有true
属性,并且无法在JavaMail中为SMTP启用SASL。 : - (
但是,您可以下载JavaMail source code,并且可以尝试编辑SMTP代码以支持SASL,其方式与IMAP代码类似。祝你好运!
答案 2 :(得分:4)
这可能对你没有帮助,但CRAM-MD5和CRAM-SHA1相当容易实现,假设你有正确的库(md5 / sha1),并且想要一个base64编码库(尽管base64的东西相当简单)在紧要关头实现自己。)
交易如下:
C: AUTH CRAM-MD5
S: 334 BASE64(NONCE)
C: BASE64(USERNAME, " ", MD5((SECRET XOR opad),MD5((SECRET XOR ipad), NONCE)))
S: 235 Authentication succeeded
其中NONCE是一次性挑战字符串,USERNAME是您尝试进行身份验证的用户名,SECRET是共享密钥(“密码”),opad是0x5C,ipad是0x36。
(CRAM-SHA1将是同一个事务,但使用SHA1()而不是MD5()来进行摘要)
所以,这是一个真正的CRAM-MD5交易的例子
C: AUTH CRAM-MD5
S: 334 PDQ1MDMuMTIyMzU1Nzg2MkBtYWlsMDEuZXhhbXBsZS5jb20+
C: dXNlckBleGFtcGxlLmNvbSA4YjdjODA5YzQ0NTNjZTVhYTA5N2VhNWM4OTlmNGY4Nw==
S: 235 Authentication succeeded
将流程备份到您获得的步骤:
S: 334 BASE64("<4503.1223557862@mail01.example.com>")
C: BASE64("user@example.com 8b7c809c4453ce5aa097ea5c899f4f87")
在计算摘要之前进一步向后退一步,得到:
S: 334 BASE64("<4503.1223557862@mail01.example.com>")
C: BASE64("user@example.com ", MD5(("password" XOR opad),MD5(("password" XOR ipad), "<4503.1223557862@mail01.example.com>")))
我想现在我把它写出来有点令人困惑,但相信我,与尝试手工制作NTLM / SPA相比,这是一件轻而易举的事。如果你有动力,实际上很容易实现。或者也许我只是花了很长时间用手掌握邮件客户端和服务器的内容,以便再清楚地思考它......
答案 3 :(得分:4)
import java.security.*;
class CRAMMD5Test
{
public static void main(String[] args) throws Exception
{
// This represents the BASE64 encoded timestamp sent by the POP server
String dataString = Base64Decoder.decode("PDAwMDAuMDAwMDAwMDAwMEBteDEuc2VydmVyLmNvbT4=");
byte[] data = dataString.getBytes();
// The password to access the account
byte[] key = new String("password").getBytes();
// The address of the e-mail account
String user = "client@server.com";
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.reset();
if (key.length > 64)
key = md5.digest(key);
byte[] k_ipad = new byte[64];
byte[] k_opad = new byte[64];
System.arraycopy(key, 0, k_ipad, 0, key.length);
System.arraycopy(key, 0, k_opad, 0, key.length);
for (int i=0; i<64; i++)
{
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
byte[] i_temp = new byte[k_ipad.length + data.length];
System.arraycopy(k_ipad, 0, i_temp, 0, k_ipad.length);
System.arraycopy(data, 0, i_temp, k_ipad.length, data.length);
i_temp = md5.digest(i_temp);
byte[] o_temp = new byte[k_opad.length + i_temp.length];
System.arraycopy(k_opad, 0, o_temp, 0, k_opad.length);
System.arraycopy(i_temp, 0, o_temp, k_opad.length, i_temp.length);
byte[] result = md5.digest(o_temp);
StringBuffer hexString = new StringBuffer();
for (int i=0;i < result.length; i++) {
hexString.append(Integer.toHexString((result[i] >>> 4) & 0x0F));
hexString.append(Integer.toHexString(0x0F & result[i]));
}
System.out.println(Base64Encoder.encode(user + " " + hexString.toString()));
}
}
答案 4 :(得分:4)
自Java Mail 1.4.4起,支持CRAM-MD5与smtp一起使用。 只需将此参数设置为您的属性即可:
props.put("mail.smtp.sasl.enable", "true");
答案 5 :(得分:2)
我尝试了真实CRAM-MD5事务的示例代码,以及RFC 2195中给出的示例。
它不起作用,因为转换为十六进制字符串不正确。例如,使用此代码,您将获得“b913a62c7eda7a495b4e6e7334d3890”而不是“b913a602c7eda7a495b4e6e7334d3890”,并且发送的身份验证字符串将不正确。
如果你下载javaMail的源代码,你会看到函数toHex的实现进入单元“DigestMD5”。使用此转换,它将起作用。
答案 6 :(得分:1)
更改:强>
for (int i=0; i<result.length; i++)
hexString.append(Integer.toHexString(0xFF & result[i]));
要强>
for (int i=0;i < result.length; i++) {
hexString.append(Integer.toHexString((result[i] >>> 4) & 0x0F));
hexString.append(Integer.toHexString(0x0F & result[i]));
}