diff --git a/msg.go b/msg.go index fc0bb57..61feda1 100644 --- a/msg.go +++ b/msg.go @@ -972,12 +972,12 @@ func (m *Msg) Subject(subj string) { // SetMessageID generates and sets a unique "Message-ID" header for the Msg. // -// This method creates a "Message-ID" string using the current process ID, random numbers, and the hostname -// of the machine. The generated ID helps uniquely identify the message in email systems, facilitating tracking -// and preventing duplication. If the hostname cannot be retrieved, it defaults to "localhost.localdomain". +// This method creates a "Message-ID" string using a randomly generated string and the hostname of the machine. +// The generated ID helps uniquely identify the message in email systems, facilitating tracking and preventing +// duplication. If the hostname cannot be retrieved, it defaults to "localhost.localdomain". // // The generated Message-ID follows the format -// "". +// "". // // References: // - https://datatracker.ietf.org/doc/html/rfc5322#section-3.6.4 @@ -986,13 +986,9 @@ func (m *Msg) SetMessageID() { if err != nil { hostname = "localhost.localdomain" } - randNumPrimary := randNum(100000000) - randNumSecondary := randNum(10000) - randString, _ := randomStringSecure(17) - procID := os.Getpid() * randNumSecondary - messageID := fmt.Sprintf("%d.%d%d.%s@%s", procID, randNumPrimary, randNumSecondary, - randString, hostname) - m.SetMessageIDWithValue(messageID) + // We have 64 possible characters, which for a 22 character string, provides approx. 132 bits of entropy. + randString, _ := randomStringSecure(22) + m.SetMessageIDWithValue(fmt.Sprintf("%s@%s", randString, hostname)) } // GetMessageID retrieves the "Message-ID" header from the Msg. diff --git a/msg_test.go b/msg_test.go index f570b02..7fcbd99 100644 --- a/msg_test.go +++ b/msg_test.go @@ -786,8 +786,8 @@ func TestMsg_SetMessageIDWithValue(t *testing.T) { // TestMsg_SetMessageIDRandomness tests the randomness of Msg.SetMessageID methods func TestMsg_SetMessageIDRandomness(t *testing.T) { var mids []string + m := NewMsg() for i := 0; i < 50_000; i++ { - m := NewMsg() m.SetMessageID() mid := m.GetMessageID() mids = append(mids, mid) diff --git a/random.go b/random.go index 2478c75..e987f00 100644 --- a/random.go +++ b/random.go @@ -11,16 +11,17 @@ import ( ) // Range of characters for the secure string generation -const cr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" +const cr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-" // Bitmask sizes for the string generators (based on 93 chars total) // // These constants define bitmask-related values used for efficient random string generation. -// The bitmask operates over 93 possible characters, and the constants help determine the +// The bitmask operates over 66 possible characters, and the constants help determine the // number of bits and indices used in the process. const ( - // letterIdxBits: Number of bits (7) needed to represent a letter index. - letterIdxBits = 7 + // letterIdxBits: Number of bits needed to represent a letter index. We have 64 possible characters + // which fit into 6 bits. + letterIdxBits = 6 // letterIdxMask: Bitmask to extract letter indices (all 1-bits for letterIdxBits). letterIdxMask = 1< tc.max { - t.Errorf("random number generation failed: %d is bigger than given value %d", rn, tc.max) - } - }) - } -} - -func TestRandomNumZero(t *testing.T) { - rn := randNum(0) - if rn != 0 { - t.Errorf("random number generation failed: %d is not zero", rn) +func BenchmarkGenerator_RandomStringSecure(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + _, err := randomStringSecure(22) + if err != nil { + b.Errorf("RandomStringFromCharRange() failed: %s", err) + } } }