Erlang SMTP发送邮件

Erlang SMTP发送邮件


https://github.com/Leptune/erlang_email


如果使用QQ邮箱  要先开通IMAP/SMTP 服务  获取授权码  秘密就填写获取到的授权码


email.erl

-module(email).
-include("email.hrl").

-export([send/1]).
%-compile(export_all).

-define(MAX_SIZE, 1024).
-define(DE, io:format("~p:~p~n", [?FILE, ?LINE])).

%% send email by email record
send(Email) when
        undefined =/= Email#email.server_ip,
        undefined =/= Email#email.account,
        undefined =/= Email#email.to_emails,
        undefined =/= Email#email.password ->
    ServerPort =
        case Email#email.server_port of
            undefined -> case Email#email.ssl of
                             true  -> ?SSL_SERV_PORT_DEF;
                             false -> ?NOT_SSL_SERV_PORT_DEF
                         end;
            Any       -> Any
        end,
    Sock =
        case Email#email.ssl of
            false -> {ok, Socket} =
                         gen_tcp:connect(Email#email.server_ip,
                                         ServerPort,
                                         [binary, {active, false}, {packet, 0}]),
                     #socket{type = tcp, sock = Socket};
            true  -> ok = ssl:start(),
                     {ok, Socket} =
                         ssl:connect(Email#email.server_ip,
                                     ServerPort,
                                     [binary, {active, false}, {packet, 0}],
                                     infinity),
                     #socket{type = ssl, sock = Socket}
        end,
    connect_email(Sock, Email),
    send_email_head(Sock, Email),
    send_email_info(Sock, Email),
    send_email_data(Sock, Email),
    end_email(Sock),
    case Sock#socket.type of
        ssl -> ssl:close(Sock#socket.sock),
               ssl:stop();
        tcp -> gen_tcp:close(Sock#socket.sock)
    end.

%% connect your email
connect_email(Sock, Email) ->
   send_socket(Sock, "HELO " ++ Email#email.account ++ "\r\n"),
   recv_socket(Sock),

   send_socket(Sock, "AUTH LOGIN\r\n"),
   recv_socket(Sock),

   send_socket(Sock, base64:encode(Email#email.account)),
   send_socket(Sock, "\r\n"),
   recv_socket(Sock),

   send_socket(Sock, base64:encode(Email#email.password)),
   send_socket(Sock, "\r\n"),
   recv_socket(Sock).

%% send email head
send_email_head(Sock, Email) ->
    send_socket(Sock, "MAIL FROM <" ++ Email#email.account ++ ">\r\n"),
    recv_socket(Sock),

    rcpt_to_emails(Sock, Email#email.to_emails),
    recv_socket(Sock).

%% send email info
send_email_info(Sock, Email) ->
    send_socket(Sock, "DATA\r\n"),
    recv_socket(Sock),

    send_socket(Sock, "FROM:<" ++ Email#email.account ++ ">\r\n"),
    recv_socket(Sock),

    Subject = unicode:characters_to_list(Email#email.subject),
    send_socket(Sock, "SUBJECT:"++ Subject ++ "\r\n").

%% send email data
send_email_data(Sock, Email) when Email#email.text       =/= undefined;
                                  Email#email.html       =/= undefined;
                                  Email#email.attachment =/= undefined ->
    send_socket(Sock, "MIME-VERSION: 1.0\r\n"),
    send_socket(Sock, "CONTENT-TYPE: multipart/mixed; BOUNDARY=\"#BOUNDARY#\"\r\n"),
    send_socket(Sock, "\r\n"),
    case Email#email.text of
        undefined -> nothing_to_do;
        _         -> send_email_text("text/plain", Email#email.text, Sock)
    end,
    case Email#email.html of
        undefined -> nothing_to_do;
        _         -> send_email_text("text/html", Email#email.html, Sock)
    end,
    case Email#email.attachment of
        undefined -> nothing_to_do;
        _         -> send_email_attachment("application/msword", Email#email.attachment, Sock)
    end;
send_email_data(_Sock, _Email) ->
    ok.

end_email(Sock) ->
    send_socket(Sock, "\r\n.\r\n"),
    recv_socket(Sock),
    send_socket(Sock, "QUIT\r\n"),
    recv_socket(Sock).

%% send email text
send_email_text(Type, FilePath, Sock) ->
    send_socket(Sock, "--#BOUNDARY#\r\n"),
    send_socket(Sock, "CONTENT-TYPE: "),
    send_socket(Sock, Type),
    send_socket(Sock, "\r\n\r\n"),

    {ok, Fd} = file:open(FilePath, [binary, read]),
    send_file_to_email(Sock, Fd, -1),
    ok = file:close(Fd),
    send_socket(Sock, "\r\n\r\n").


%% send email other type
send_email_attachment(_Type, [], _Sock) ->
    nothing_to_return;
send_email_attachment(Type, [FilePath | Rest], Sock) ->
    send_socket(Sock, "--#BOUNDARY#\r\n"),
    send_socket(Sock, "CONTENT-TYPE: "),
    send_socket(Sock, Type),
    send_socket(Sock, "; NAME="),
    send_socket(Sock, misc:basename(FilePath)),
    send_socket(Sock, "\r\n"),
    send_socket(Sock, "CONTENT-TRANSFER-ENCODING: base64\r\n"),
    send_socket(Sock, "\r\n"),

    {ok, Fd} = file:open(FilePath, [binary, read]),
    io:format("Client: Send ~p to server....~n", [FilePath]),
    send_file_to_email(Sock, Fd, 0),
    ok = file:close(Fd),
    send_socket(Sock, "\r\n\r\n"),
    send_email_attachment(Type, Rest, Sock).

%% send file
send_file_to_email(Sock, Fd, Base64Flag) ->
    case file:read(Fd, ?MAX_SIZE) of
        {ok, Data} ->
            case Base64Flag of
                -1 -> ok = send(Sock, Data);
                0  -> ok = send(Sock, base64:encode(Data))
            end,
            send_file_to_email(Sock, Fd, Base64Flag);
        eof             -> eof;
        {error, Reason} -> io:format("read failed: ~p~n", [Reason])
    end.

%% her email address
rcpt_to_emails(_Sock, []) ->
    ok;
rcpt_to_emails(Sock, [ToEmail | Rest]) ->
    send_socket(Sock, "RCPT TO <" ++ ToEmail ++ ">\r\n"),
    rcpt_to_emails(Sock, Rest).

%% send socket
send_socket(Sock, Data) when is_list(Data)->
    send_socket(Sock, unicode:characters_to_binary(Data));
send_socket(Sock, Data) when is_binary(Data)->
    io:format("Client: ~p~n", [Data]),
    ok = send(Sock, Data).

%% recv socket
recv_socket(Sock) ->
    case recv(Sock, 0) of
        {ok   , Packet} -> io:format("Server: ~p~n", [binary_to_list(Packet)]);
        {error, Reason} -> io:format("Server: recv failed: ~p~n", [Reason])
    end.

%% send data to server via tcp or ssl
send(Sock, Data) when Sock#socket.type =:= tcp ->
    gen_tcp:send(Sock#socket.sock, Data);
send(Sock, Data) when Sock#socket.type =:= ssl ->
    ssl:send(Sock#socket.sock, Data).

%% recv data to server via tcp or ssl
recv(Sock, Opinion) when Sock#socket.type =:= tcp ->
    gen_tcp:recv(Sock#socket.sock, Opinion);
recv(Sock, Opinion) when Sock#socket.type =:= ssl ->
    ssl:recv(Sock#socket.sock, Opinion).


email.hrl

-record(email, {
          server_ip   , % (必填) 邮件服务器ip(如: "smtp.qq.com")
          account     , % (必填) 你自己的邮箱名(如: "[email protected]")
          password    , % (必填) 密码
          to_emails   , % (必填) 要发往的邮箱(格式:["","",...])(如: ["[email protected]", "[email protected]"])
          server_port , % (可选) 要传整数。如ssl为true,则默认端口为465, 否则默认端口为25,也可以手动指定
          ssl = true  , % (可选) 是否需要ssl加密(true 或 false)
          subject = "", % (可选) 邮件标题
          text        , % (可选) (正文)将文本内容发往邮箱,text的值为存放该内容的文件路径(路径以'/'分隔,不要以'\\'分隔)
          html        , % (可选) (正文)将网页内容发往邮箱,html值为该网页文件路径(注: 两个正文最多只能选一项。都选了只显示html)
          attachment    % (可选) (附件)要发往邮箱的文件路径(格式:["", "",...],如:["test.doc","test.tar"])(注意后缀名要对,否则不能预览)
}).

-record(socket, {type, sock}).

-define(SSL_SERV_PORT_DEF, 465).
-define(NOT_SSL_SERV_PORT_DEF, 25).


-module(misc).
-export([index/2, split_binary_by_digit/2, basename/1]).

%% 取出二进制或列表里对应下标(从0开始)的值
index(Data, Index) when is_binary(Data) ->
    index(binary_to_list(Data), Index);
index(Data, Index)
    when is_list(Data), is_integer(Index),
    Index >= 0, Index < length(Data) ->
    index(Data, Index, 0).

index([D0 | _DRest], GivenIndex, CurrIndex)
    when GivenIndex =:= CurrIndex ->
    D0;
index([_D0 | DRest], GivenIndex, CurrIndex) ->
    index(DRest, GivenIndex, CurrIndex + 1).

%% 将二进制Bin按数字Digit分隔成左右两个二进制数
split_binary_by_digit(Bin, Digit)
    when is_binary(Bin),is_integer(Digit) ->
    split_binary_by_digit(Bin, Digit, <<>>).

split_binary_by_digit(<<>>, _Digit, _Left) ->
    {error, unmatched};
split_binary_by_digit(<<N, Rest/binary>>, Digit, Left) when N =/= Digit ->
    split_binary_by_digit(Rest, Digit, <<Left/binary, N>>);
split_binary_by_digit(<<_N, Rest/binary>>, _Digit, Left) ->
    {ok, Left, Rest}.

%% 取出文件路径中的文件名
basename(FilePath) when is_list(FilePath) ->
    case lists:member($/, FilePath) of
        false -> FilePath;
        true  -> basename(lists:reverse(FilePath), [])
    end.

basename([C | _Rest], BaseName) when C =:= $/ ->
    BaseName;
basename([C | Rest], BaseName) ->
    basename(Rest, [C | BaseName]).



示例

%%TarMail 发送到的邮箱地址  ,Title 邮件标题 , Context  邮件内容 
send_mail(TarMail,Title,Context) ->
	
	FileName = "lastEmailContext.txt",
	
	{ok,NowPath}=file:get_cwd(),
  	
	FileDir = NowPath ++"/../include/",
	FilePath = FileDir++FileName,
	
	case filelib:is_dir(FileDir) of
		false->
			?Log([FileDir,"does not exist"]);
		true ->
			case file:open(FilePath, write) of
				{ok,Conf} -> 
					io:format(Conf, "~s", [Context]),
					file:close(Conf);
				_ ->
					?Log(["open file failed",FilePath])
			
			end
	end,

	email:send(#email{server_ip   = "smtp.qq.com",
				account     = "[email protected]",
                password    = ">XXXXXXX",
                subject     = Title,
				text		= FilePath,
                %html        = "testfiles/test.html",
                %attachment  = ["testfiles/test.doc", "testfiles/test.html", "testfiles/test.tar", "testfiles/test.txt"],
                to_emails   = [TarMail]
			   }).





你可能感兴趣的:(Erlang SMTP发送邮件)