1. 程式人生 > >[轉載] 使用Bugzilla,你肯定會遇到的坑。

[轉載] 使用Bugzilla,你肯定會遇到的坑。

使用Bugzilla,你肯定會遇到的坑。

2018年06月01日 09:36:32 美少女程式猿

 

最近和幾個朋友一起做使用者態協議棧開源專案 NtyTcp ,純業餘愛好,個人情懷。剛剛開始做有好多的Bug,故搭建了一個Bugzilla,用來上傳Bug的。

有幾個開發朋友想在 bug.ntytcp.com提交bug,不能註冊,因為不能發郵件。至於為什麼不能傳送郵件?因為阿里雲把25埠封了,使用smtp不能傳送。

使用465埠傳送,發現發不出來,又找不到原因。硬著頭皮比Bugzilla的原始碼看了一下。可恨的是自己並沒有寫過perl程式碼。

 

於是用了兩天時間連學帶看就把bugzilla的原始碼看了一遍。然後把bugzilla郵件傳送的部分重寫了一下。先把bugzilla郵件傳送部分貼出來。

bugzilla/mailer.pm

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

sub MessageToMTA {

my ($msg$send_now) = (@_);

my $method = Bugzilla->params->{'mail_delivery_method'};

return if $method eq 'None';

 

if (Bugzilla->params->{

'use_mailer_queue'}

&& ! $send_now

&& ! Bugzilla->dbh->bz_in_transaction()

) {

Bugzilla->job_queue->insert('send_mail', { msg => $msg });

return;

}

 

my $dbh = Bugzilla->dbh;

 

my $email ref($msg) ? $msg : Bugzilla::MIME->new($msg);

 

# If we're called from within a transaction, we don't want to send the

# email immediately, in case the transaction is rolled back. Instead we

# insert it into the mail_staging table, and bz_commit_transaction calls

# send_staged_mail() after the transaction is committed.

if (! $send_now && $dbh->bz_in_transaction()) {

# The e-mail string may contain tainted values.

my $string $email->as_string;

trick_taint($string);

 

my $sth $dbh->prepare("INSERT INTO mail_staging (message) VALUES (?)");

$sth->bind_param(1, $string$dbh->BLOB_TYPE);

$sth->execute;

return;

}

 

my $from $email->header('From');

 

my $hostname;

my $transport;

if ($method eq "Sendmail") {

if (ON_WINDOWS) {

$transport = Bugzilla::Sender::Transport::Sendmail->new({ sendmail => SENDMAIL_EXE });

}

else {

$transport = Bugzilla::Sender::Transport::Sendmail->new();

}

}

else {

# Sendmail will automatically append our hostname to the From

# address, but other mailers won't.

my $urlbase = Bugzilla->params->{'urlbase'};

$urlbase =~ m|//([^:/]+)[:/]?|;

$hostname = $1 || 'localhost';

$from .= "\@$hostname" if $from !~ /@/;

$email->header_set('From'$from);

# Sendmail adds a Date: header also, but others may not.

if (!defined $email->header('Date')) {

$email->header_set('Date', time2str("%a, %d %b %Y %T %z"time()));

}

}

 

if ($method eq "SMTP") {

my ($host$port) = split(/:/, Bugzilla->params->{'smtpserver'}, 2);

$transport = Bugzilla->request_cache->{smtp} //=

Email::Sender::Transport::SMTP::Persistent->new({

host  => $host,

defined($port) ? (port => $port) : (),

sasl_username => Bugzilla->params->{'smtp_username'},

sasl_password => Bugzilla->params->{'smtp_password'},

helo => $hostname,

ssl => Bugzilla->params->{'smtp_ssl'},

debug => Bugzilla->params->{'smtp_debug'} });

}

 

Bugzilla::Hook::process('mailer_before_send', { email => $email });

 

return if $email->header('to') eq '';

 

if ($method eq "Test") {

my $filename = bz_locations()->{'datadir'} . '/mailer.testfile';

open TESTFILE, '>>'$filename;

# From - <date> is required to be a valid mbox file.

print TESTFILE "\n\nFrom - " $email->header('Date') . "\n" $email->as_string;

close TESTFILE;

}

else {

# This is useful for Sendmail, so we put it out here.

local $ENV{PATH} = SENDMAIL_PATH;

eval { sendmail($email, { transport => $transport }) };

if ([email protected]) {

ThrowCodeError('mail_send_error', { msg => [email protected]>message, mail => $email });

}

}

}

 

使用的sendmail($email, {transport=> $transport}), 傳送。由於系統的sendmail沒有配置好,傳送不出來。

自己寫了一版單獨用perl傳送郵件的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

#!/usr/bin/perl

 

use Net::SMTP::SSL;

use MIME::Base64;

use MIME::Lite;

 

my $msg = MIME::Lite->new(

From=>'[email protected]',

To=>'[email protected]',

Subject=>'First Email',

Data=>'nihao',

Type=>'text/html'

);

 

$account="[email protected]";

$password="your password";

$smtp = Net::SMTP::SSL->new(

Host => 'smtp.host.com',

Port => 465,

Timeout => 120,

Debug=>1

); # connect to an SMTP server

die "Couldn't open connection: $!" if (!defined $smtp );

#$smtp->auth($account,$password);

 

$smtp->datasend("AUTH LOGIN\r\n");

$smtp->datasend(encode_base64('[email protected]')); # username

$smtp->datasend(encode_base64('your password')); # password

 

$smtp->mail('[email protected]');

$smtp->to('[email protected]');

 

$smtp->data();

 

$smtp->datasend($msg->as_string());

 

$smtp->datasend("Blah\r\n\r\n");

 

$smtp->dataend();

 

相信從程式碼風格來看,就是第一次寫perl   。^_^  。 ^_^

這版是可以傳送郵件的。

但是跟bugzilla的mailer.pm 傳送差別很大。沒辦法整合。

 

於是又換了一種寫法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

#!/usr/bin/perl

 

use strict;

use warnings;

 

use Email::Sender::Simple qw(sendmail);

use Email::Sender::Transport::SMTP ();

use Email::Simple ();

use Email::Simple::Creator ();

use Email::Sender::Transport::SMTP::TLS;

use Email::Sender::Transport::SMTP::Persistent;

use Email::Sender::Transport::SMTPS;

use Net::SMTP::SSL;

use MIME::Base64;

 

my $smtpserver   'smtp.host.com';

my $smtpport     = 465;

my $smtpuser     '[email protected]';

my $smtppassword 'your password';

my $smtpto       '[email protected]';

my $hostname     'localhost.localdomain';

 

my $transport = Email::Sender::Transport::SMTP::Persistent->new({

            host  => $smtpserver,

            defined($smtpport) ? (port => $smtpport) : (),

            sasl_username => $smtpuser,

            sasl_password => $smtpuser,

            helo => $hostname,

            ssl => 1,

            debug => 1 });

 

my $email = Email::Simple->create(

  header => [

    To      => $smtpto,

    From    => $smtpuser,

    Subject => 'Hi!',

  ],

  body => "This is my message\n",

);

 

#try {

#eval {sendmail($email, { transport => $transport }) };

#}catch {

#die "Error sending email: $_";

my $smtp = Net::SMTP::SSL->new(

            Host  => $smtpserver,

            Port => $smtpport,

            Timeout => 120,

            Debug => 1

        );

        die "Couldn't open connection: $!" if (!defined $smtp );

 

        #$smtp->auth(Bugzilla->params->{'smtp_username'}, Bugzilla->params->{'smtp_password'});

        $smtp->datasend("AUTH LOGIN\n");

        $smtp->datasend(encode_base64($smtpuser));

        $smtp->datasend(encode_base64($smtppassword));

 

        $smtp->mail($smtpuser);

        $smtp->to($smtpto);

 

        $smtp->data();

        $smtp->datasend($email->as_string());

 

        $smtp->datasend("\r\n\r\n");

        $smtp->dataend();

        $smtp->quit();

 

這個程式碼的風格就像那麼回事了,就寫過perl程式碼的人了 。^_^。^_^

將mailer.pm 的程式碼整合。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

sub MessageToMTA {

    my ($msg$send_now) = (@_);

    my $method = Bugzilla->params->{'mail_delivery_method'};

    return if $method eq 'None';

 

    if (Bugzilla->params->{'use_mailer_queue'}

        && ! $send_now

        && ! Bugzilla->dbh->bz_in_transaction()

    ) {

        Bugzilla->job_queue->insert('send_mail', { msg => $msg });

        return;

    }

 

    my $dbh = Bugzilla->dbh;

 

    my $email ref($msg) ? $msg : Bugzilla::MIME->new($msg);

 

    # If we're called from within a transaction, we don't want to send the

    # email immediately, in case the transaction is rolled back. Instead we

    # insert it into the mail_staging table, and bz_commit_transaction calls

    # send_staged_mail() after the transaction is committed.

    if (! $send_now && $dbh->bz_in_transaction()) {

        # The e-mail string may contain tainted values.

        my $string $email->as_string;

        trick_taint($string);

 

        my $sth $dbh->prepare("INSERT INTO mail_staging (message) VALUES (?)");

        $sth->bind_param(1, $string$dbh->BLOB_TYPE);

        $sth->execute;

        return;

    }

 

    my $from $email->header('From');

 

    my $hostname;

    my $transport;

    if ($method eq "Sendmail") {

        if (ON_WINDOWS) {

            $transport = Bugzilla::Sender::Transport::Sendmail->new({ sendmail => SENDMAIL_EXE });

        }

        else {

            $transport = Bugzilla::Sender::Transport::Sendmail->new();

        }

    }

    else {

        # Sendmail will automatically append our hostname to the From

        # address, but other mailers won't.

        my $urlbase = Bugzilla->params->{'urlbase'};

        $urlbase =~ m|//([^:/]+)[:/]?|;

        $hostname = $1 || 'localhost';

        $from .= "\@$hostname" if $from !~ /@/;

        $email->header_set('From'$from);

 

        # Sendmail adds a Date: header also, but others may not.

        if (!defined $email->header('Date')) {

            $email->header_set('Date', time2str("%a, %d %b %Y %T %z"time()));

        }

    }

    my ($host$port) = split(/:/, Bugzilla->params->{'smtpserver'}, 2);

    if ($method eq "SMTP") {

#        my ($host, $port) = split(/:/, Bugzilla->params->{'smtpserver'}, 2);

        $transport = Bugzilla->request_cache->{smtp} //=

          Email::Sender::Transport::SMTP::Persistent->new({

            host  => $host,

            defined($port) ? (port => $port) : (),

            sasl_username => Bugzilla->params->{'smtp_username'},

            sasl_password => Bugzilla->params->{'smtp_password'},

            helo => $hostname,

            ssl => Bugzilla->params->{'smtp_ssl'},

            debug => Bugzilla->params->{'smtp_debug'} });

 

    }

 

    Bugzilla::Hook::process('mailer_before_send', { email => $email });

 

    return if $email->header('to') eq '';

 

    if ($method eq "Test") {

        my $filename = bz_locations()->{'datadir'} . '/mailer.testfile';

        open TESTFILE, '>>'$filename;

        # From - <date> is required to be a valid mbox file.

        print TESTFILE "\n\nFrom - " $email->header('Date') . "\n" $email->as_string;

        close TESTFILE;

    }

    else {

        # This is useful for Sendmail, so we put it out here.

#        local $ENV{PATH} = SENDMAIL_PATH;

#        eval { sendmail($email, { transport => $transport }) };

#        if ([email protected]) {

#            ThrowCodeError('mail_send_error', { msg => [email protected]>message, mail => $email });

#        }

        my $smtp = Net::SMTP::SSL->new(

            Host  => $host,

            Port => $port,

            Timeout => 120,

            Debug => 1

        );

        die "Couldn't open connection: $!" if (!defined $smtp );

 

        #$smtp->auth(Bugzilla->params->{'smtp_username'}, Bugzilla->params->{'smtp_password'});

        $smtp->datasend("AUTH LOGIN\n");

        $smtp->datasend(encode_base64(Bugzilla->params->{'smtp_username'}));

        $smtp->datasend(encode_base64(Bugzilla->params->{'smtp_password'}));

 

        $smtp->mail(Bugzilla->params->{'smtp_username'});

        $smtp->to($email->header('to'));

 

        $smtp->data();

        $smtp->datasend($email->as_string());

 

        $smtp->datasend("\r\n\r\n");

        $smtp->dataend();

        $smtp->quit();

    }

}

 

主要是將郵件傳送方式修改了。

1

2

3

4

5

        local $ENV{PATH} = SENDMAIL_PATH;

        eval { sendmail($email, { transport => $transport }) };

        if ([email protected]) {

            ThrowCodeError('mail_send_error', { msg => [email protected]>message, mail => $email });

        }

換成了

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

        my $smtp = Net::SMTP::SSL->new(

            Host  => $host,

            Port => $port,

            Timeout => 120,

            Debug => 1

        );

        die "Couldn't open connection: $!" if (!defined $smtp );

 

        #$smtp->auth(Bugzilla->params->{'smtp_username'}, Bugzilla->params->{'smtp_password'});

        $smtp->datasend("AUTH LOGIN\n");

        $smtp->datasend(encode_base64(Bugzilla->params->{'smtp_username'}));

        $smtp->datasend(encode_base64(Bugzilla->params->{'smtp_password'}));

 

        $smtp->mail(Bugzilla->params->{'smtp_username'});

        $smtp->to($email->header('to'));

 

        $smtp->data();

        $smtp->datasend($email->as_string());

 

        $smtp->datasend("\r\n\r\n");

        $smtp->dataend();

        $smtp->quit();

 

bugzilla的程式碼還是寫的很人性化的,沒有寫過perl程式碼的,一看都能知道個大概。向Bugzilla的作者致敬。

至於郵件傳送的流程,大家可以參照rfc822,不要隨便相信網上的程式碼。