[![Hex Version]( "Hex version")](
[![Apache 2.0 License]( "Apache 2.0 license")](

POP3 client library for Erlang. It is derived from the original "epop" Erlang package which includes both a POP server and client.

epop author: [*Torbjörn Törnkvist*]( when working at Software Engineering Research Center, SERC, in Melbourne

### Documentation ###

[epop 2.9 documentation](

[RFC 1939](

Note that the proposed standards [RFC 2449]( (Pipelining), [RFC 1734/5034]( (AUTH), [RFC 2595]( (STLS), [RFC 1082]( (XTND) are NOT supported.

### Changes ###
    2023-11-29 Nico Hoogervorst  - v1.4, Erlang / OTP 26 upgrade. Pass on cacerts to ssl:connect. 
                                   'ssl' parameter can now be false, true, list with ssl:connect options, or
                                   a ssl:connect compatible function. A cacertfile can be passed in the ssl list.
    2019-05-21 Nico Hoogervorst  - v1.3.1, Replaced obsolete functions; string:tokens, string:str, string:substr, string:cspan.    
    2019-01-26 Nico Hoogervorst  - v1.3, added line-by-line/streaming interface. Added NOOP. Stricter byte-stuffing. eunit tests.
    2018-11-09 Nico Hoogervorst  - v1.2, case-insensitive header lookup. Added erlpop as package 'pop3client' in
    2017-06-13 Nico Hoogervorst  - Added 'bin_retrieve' get binary data instead of character list to reduce memory consumption
    2016-08-05 Nico Hoogervorst  - Erlang V8.0.2 / OTP 19 upgrade
    2013-04-18 Erik Søe Sørensen - Add an email address parser 'epop_address' (RFC5322)
    2013-04-17 Erik Søe Sørensen - Erlang/OTP 15 upgrade, "TOP" fix; rebarify
    2013-01-31 Wes James         - update ssl start command to current erlang api 
    2009-10-06 Harish Mallipeddi - Added `epop_message` to parse retrieved email messages.
    2008-09-10 Harish Mallipeddi - Added SSL support (epop_client can be now be used with services like GMail which require SSL).

### License ###

[Erlang public license]( is deprecated in June 2015 and replaced with Apache 2.0 license

### Usage Erlang ###

    rebar3 compile
    erl -pa ./_build/default/lib/pop3client/ebin
    1> User = "".
    2> {ok, Connection} = epop_client:connect(User, "yourpassword",
    2>                                    [ {addr, ""}, {port, 995}, {user, User}, ssl ] ).
    3> {ok, {TotalCount, TotalSize}} = epop_client:stat(Connection).
    4> {ok, TopContent} = epop_client:top(Connection, 1, 20).
    5> {message, HeaderList, Body} = epop_message:parse(TopContent).
    6> {ok, MailContent} = epop_client:bin_retrieve(Connection, 1).
    7> {message, BinHeaderList, BinBody} = epop_message:bin_parse(MailContent).
    8> {ok, Date} = epop_message:find_header(BinHeaderList, <<"Date">>). 
    9> epop_client:quit(Connection).

  *NOTE*: It's important to call epop_client:quit/1 at the end, as it's responsible for closing (tcp/tls) socket.
  The retrieval of an email can also be done line-by-line using retrieve_start, retrieve_next, retrieve_after. 
  Always call the retrieve_after when ready. 
    erl -pa ./_build/default/lib/pop3client/ebin
    1> {ok, Acc} = epop_client:retrieve_start(Connection, 1).
    2> {HaltOrNewLine, NewAcc} = epop_client:retrieve_next(Acc).
    3> ok = epop_client:retrieve_after(NewAcc).

  Address list parser, like [RFC 5322](

    erl -pa ./_build/default/lib/pop3client/ebin
    1> {ok, AddressList} = epop_address:parse_list("\"hendrik\" <>, philipp <>").    
    2> {ok,[Group]} = epop_address:parse_list("Managing,;").
    {ok,[{group,"Managing Partners",
    3> epop_address:expand_groups([Group]).

### Usage Elixir ###

    Specially note how easy it is to create an Elixir stream

    iex -S mix
    iex(1)> user = ''
    iex(2)> {ok, connection} = :epop_client.connect(user, 'yourpassword', 
    ...(2)>                                     [ {:addr, ''}, {:port, 995}, {:user, user}, :ssl] )
    iex(3)> {:ok, {total_count, total_size}} = :epop_client.stat(connection)
    iex(4)> # read headers and 20 lines of the body of the first email
    iex(5)> {:ok, mail_content} =, 1, 20)
    iex(6)> # separate headers and body
    iex(7)> {:message, header_list, body} = :epop_message.parse(mail_content)
    iex(8)> # create lazy stream resource for the first email
    iex(9)> mail1stream = apply(Stream, :resource, :epop_client.retrieve_resource_functions(connection, 1))
    iex(10)> # read from the stream. Example:
    iex(11)> mail1stream |> Enum.find(fn(val) -> String.contains?(val, "Waldo") end)  |> String.trim
    iex(12)> # use the stream again and it will read the whole mail again. Now write to file:
    iex(13)> output_file =!("mail1.eml", [:write, :delayed_write])
    iex(14)> mail1stream |> Enum.into(output_file)
    iex(15)> :epop_client.quit(connection)

  *NOTE*: It's important to call epop_client:quit/1 at the end, as it's responsible for closing (tcp/tls) socket.
### escript example for downloading emails ###

    wget -q

    escript pop3client_downloader --help
    escript pop3client_downloader
    escript pop3client_downloader --username --password yourpassword --max 10 --output myinbox