6

我需要从 Java 通过(外部)SMTP 服务器发送电子邮件,但是该服务器只接受 CRAM-MD5 身份验证,JavaMail 不支持这种身份验证。

发送这些电子邮件的好方法是什么?(它必须是 Java 语言。)

4

7 回答 7

6

这是线程,它说您需要添加以下属性:

props.put("mail.smtp.auth.mechanisms", "CRAM-MD5")

在 Geronimo 实现中还有CramMD5Authenticator

希望它有助于解决这个老问题。

于 2012-08-24T14:04:47.467 回答
5

从 Java Mail 1.4.4 开始,支持 CRAM-MD5 与 smtp 一起使用。只需将此参数设置为您的属性,它将起作用:

props.put("mail.smtp.sasl.enable", "true");

于 2012-08-28T09:03:34.107 回答
4

这并不能直接帮助您,但是,如果您将布尔mail.imap.sasl.enable属性设置为true.

不幸的是,没有mail.smtp.sasl.enable属性,并且无法在 JavaMail 中为 SMTP 启用 SASL。:-(

但是,您可以下载JavaMail 源代码,并且您可以尝试以与 IMAP 代码类似的方式编辑 SMTP 代码以支持 SASL。祝你好运!

于 2008-10-09T11:52:48.137 回答
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 相比,它轻而易举。如果你有动力,它实际上很容易实现。或者,也许我只是在邮件客户端和服务器的内部花费了很长时间才能清楚地考虑它......

于 2008-10-09T13:32:24.940 回答
4

JAVA中非常简单的CRAMMD5程序


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()));
    }
}
于 2008-12-31T17:46:13.843 回答
2

我尝试了真实 CRAM-MD5 事务示例中的代码,以及 RFC 2195 中给出的示例。

它不起作用,因为转换为十六进制字符串不正确。例如,使用此代码,您将获得“b913a62c7eda7a495b4e6e7334d3890”而不是“b913a602c7eda7a495b4e6e7334d3890”,并且发送的身份验证字符串将不正确。

如果你下载javaMail的源代码,你会看到函数toHex的实现到单元“DigestMD5”中。使用此转换,它将起作用。

于 2009-01-22T09:58:50.143 回答
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]));
}
于 2009-02-03T22:28:33.040 回答