@@ -2,6 +2,8 @@ open Lwt.Infix
2
2
open Colombe
3
3
4
4
let ( <.> ) f g x = f (g x)
5
+ let ( >> ? ) = Lwt_result. bind
6
+ let error_msgf fmt = Fmt. kstr (fun msg -> Error (`Msg msg)) fmt
5
7
6
8
module Lwt_scheduler = Sigs. Make (Lwt )
7
9
@@ -46,55 +48,81 @@ let open_sendmail_with_starttls_error = function
46
48
| Error (#Sendmail_with_starttls. error as err ) -> Error err
47
49
48
50
let open_error = function Ok _ as v -> v | Error (#error as err ) -> Error err
49
- let failwith_error_msg = function Ok v -> v | Error (`Msg msg ) -> failwith msg
50
- let failf fmt = Fmt. kstr (fun err -> Lwt. fail (Failure err)) fmt
51
+ let authenticator = Lazy. from_fun Ca_certs. authenticator
52
+
53
+ let tls_config user's_tls_config user's_authenticator =
54
+ match user's_tls_config with
55
+ | Some cfg -> Ok cfg
56
+ | None ->
57
+ let ( let * ) = Result. bind in
58
+ let * authenticator =
59
+ match (Lazy. force authenticator, user's_authenticator) with
60
+ | Ok authenticator , None -> Ok authenticator
61
+ | _ , Some authenticator -> Ok authenticator
62
+ | (Error _ as err ), None -> err in
63
+ Tls.Config. client ~authenticator ()
51
64
52
65
let resolve host ?port service =
53
66
Lwt_unix. getprotobyname " tcp" >> = fun tcp ->
54
67
Lwt_unix. getaddrinfo host service Unix. [ AI_PROTOCOL tcp.Unix. p_proto ]
55
68
>> = fun result ->
56
69
match (result, port) with
57
70
| [] , None ->
58
- failf
59
- " Service %S is not recognized by your system or the host %s is \
60
- unreachable"
61
- service host
71
+ Lwt. return
72
+ (error_msgf
73
+ " Service %S is not recognized by your system or the host %s is \
74
+ unreachable"
75
+ service host)
62
76
| [] , Some port -> (
63
77
Lwt_unix. gethostbyname host >> = function
64
- | { Unix. h_addr_list = [||]; _ } -> failf " Host %s unreachable" host
78
+ | { Unix. h_addr_list = [||]; _ } ->
79
+ Lwt. return (error_msgf " Host %s unreachable" host)
65
80
| { Unix. h_addr_list; _ } ->
66
- Lwt. return (Unix. ADDR_INET (h_addr_list.(0 ), port)))
81
+ Lwt. return_ok (Unix. ADDR_INET (h_addr_list.(0 ), port)))
67
82
| ai :: _ , _ ->
68
83
match (port, ai.ai_addr) with
69
84
| Some port , Unix. ADDR_INET (inet_addr , _ ) ->
70
- Lwt. return (Unix. ADDR_INET (inet_addr, port))
71
- | _ -> Lwt. return ai.ai_addr
85
+ Lwt. return_ok (Unix. ADDR_INET (inet_addr, port))
86
+ | _ -> Lwt. return_ok ai.ai_addr
87
+
88
+ let pp_addr ppf = function
89
+ | Unix. ADDR_INET (inet_addr , port ) ->
90
+ Fmt. pf ppf " %s:%d" (Unix. string_of_inet_addr inet_addr) port
91
+ | Unix. ADDR_UNIX str -> Fmt. pf ppf " <%s>" str
72
92
73
- let submit ?encoder ?decoder ?queue ~destination ?port ~domain ?authenticator
74
- ?authentication sender recipients mail =
93
+ let connect socket addr =
94
+ Lwt. pick
95
+ [
96
+ Lwt_unix. sleep 5.0 > |= Fun. const `Timeout ;
97
+ Lwt_unix. connect socket addr > |= Fun. const `Connected ;
98
+ ]
99
+ >> = function
100
+ | `Timeout -> Lwt. return (error_msgf " Connection to %a timeout" pp_addr addr)
101
+ | `Connected -> Lwt. return_ok ()
102
+
103
+ let submit ?encoder ?decoder ?queue ~destination ?port ~domain
104
+ ?cfg :user's_tls_config ?authenticator :user's_authenticator ?authentication
105
+ sender recipients mail =
75
106
let mail () = Lwt_scheduler. inj (mail () ) in
107
+ Lwt. return (tls_config user's_tls_config user's_authenticator)
108
+ >> ? fun tls_cfg ->
76
109
let protocol =
77
- match (port, authenticator) with
78
- | Some 587 , Some authenticator ->
79
- `With_starttls
80
- (failwith_error_msg (Tls.Config. client ~authenticator () ))
81
- | (Some 587 | None ), None -> `Clear
82
- | (Some _ | None ), Some authenticator ->
83
- `With_tls (failwith_error_msg (Tls.Config. client ~authenticator () ))
84
- | Some _ , None -> `Clear in
85
- match (protocol, authentication) with
86
- | `With_starttls tls , _ ->
110
+ match port with
111
+ | Some 587 -> `With_starttls tls_cfg
112
+ | Some _ | None -> `With_tls tls_cfg in
113
+ match protocol with
114
+ | `With_starttls tls ->
87
115
(match (destination, port) with
88
116
| `Ipaddr ipaddr , Some port ->
89
- Lwt. return (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, port))
117
+ Lwt. return_ok (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, port))
90
118
| `Ipaddr ipaddr , None ->
91
- Lwt. return (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, 587 ))
119
+ Lwt. return_ok (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, 587 ))
92
120
| `Domain_name domain_name , port ->
93
121
resolve (Domain_name. to_string domain_name) ?port " submission" )
94
- >> = fun addr ->
122
+ >> ? fun addr ->
95
123
let socket =
96
124
Lwt_unix. socket (Unix. domain_of_sockaddr addr) Unix. SOCK_STREAM 0 in
97
- Lwt_unix. connect socket addr >> = fun () ->
125
+ connect socket addr >> ? fun () ->
98
126
let ic = Lwt_io. of_fd ~mode: Lwt_io. Input socket in
99
127
let oc = Lwt_io. of_fd ~mode: Lwt_io. Output socket in
100
128
let ctx =
@@ -105,50 +133,31 @@ let submit ?encoder ?decoder ?queue ~destination ?port ~domain ?authenticator
105
133
|> Lwt_scheduler. prj
106
134
> |= open_sendmail_with_starttls_error
107
135
> |= open_error
108
- | `Clear , Some _ -> Lwt. return_error `Encryption_required
109
- | `Clear , None ->
110
- (match (destination, port) with
111
- | `Ipaddr ipaddr , Some port ->
112
- Lwt. return (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, port))
113
- | `Ipaddr ipaddr , None ->
114
- Lwt. return (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, 587 ))
115
- | `Domain_name domain_name , port ->
116
- resolve (Domain_name. to_string domain_name) ?port " submission" )
117
- >> = fun addr ->
118
- let socket =
119
- Lwt_unix. socket (Unix. domain_of_sockaddr addr) Unix. SOCK_STREAM 0 in
120
- Lwt_unix. connect socket addr >> = fun () ->
121
- let ic = Lwt_io. of_fd ~mode: Lwt_io. Input socket in
122
- let oc = Lwt_io. of_fd ~mode: Lwt_io. Output socket in
123
- let ctx = Colombe.State.Context. make ?encoder ?decoder () in
124
- Sendmail. sendmail lwt rdwr { ic; oc } ctx ~domain ?authentication sender
125
- recipients mail
126
- |> Lwt_scheduler. prj
127
- > |= open_sendmail_error
128
- > |= (function Error err -> Error (err :> error ) | Ok value -> Ok value)
129
- > |= open_error
130
- | `With_tls tls , _ ->
136
+ | `With_tls tls ->
131
137
(match (destination, port) with
132
138
| `Ipaddr ipaddr , Some port ->
133
139
let addr = Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, port) in
134
140
let socket =
135
141
Lwt_unix. socket (Unix. domain_of_sockaddr addr) Unix. SOCK_STREAM 0
136
142
in
137
- Lwt_unix. connect socket addr >> = fun () ->
143
+ connect socket addr >> ? fun () ->
138
144
Tls_lwt.Unix. client_of_fd tls socket
139
145
> |= Tls_lwt. of_t ~close: (fun () -> Lwt_unix. close socket)
146
+ > |= Result. ok
140
147
| `Ipaddr ipaddr , None ->
141
148
let addr = Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, 465 ) in
142
149
let socket =
143
150
Lwt_unix. socket (Unix. domain_of_sockaddr addr) Unix. SOCK_STREAM 0
144
151
in
145
- Lwt_unix. connect socket addr >> = fun () ->
152
+ connect socket addr >> ? fun () ->
146
153
Tls_lwt.Unix. client_of_fd tls socket
147
154
> |= Tls_lwt. of_t ~close: (fun () -> Lwt_unix. close socket)
155
+ > |= Result. ok
148
156
| `Domain_name domain_name , port ->
149
157
let port = Option. value ~default: 465 port in
150
- Tls_lwt. connect_ext tls (Domain_name. to_string domain_name, port))
151
- >> = fun (ic , oc ) ->
158
+ Tls_lwt. connect_ext tls (Domain_name. to_string domain_name, port)
159
+ > |= Result. ok)
160
+ >> ? fun (ic , oc ) ->
152
161
let ctx = Colombe.State.Context. make ?encoder ?decoder () in
153
162
Sendmail. sendmail lwt rdwr { ic; oc } ctx ~domain ?authentication sender
154
163
recipients mail
@@ -157,41 +166,29 @@ let submit ?encoder ?decoder ?queue ~destination ?port ~domain ?authenticator
157
166
> |= (function Error err -> Error (err :> error ) | Ok value -> Ok value)
158
167
> |= open_error
159
168
160
- let sendmail ?encoder ?decoder ?queue ~destination ?port ~domain ?authenticator
161
- ?authentication sender recipients mail =
169
+ let sendmail ?encoder ?decoder ?queue ~destination ?port ~domain
170
+ ?cfg :user's_tls_config ?authenticator :user's_authenticator ?authentication
171
+ sender recipients mail =
162
172
(match (destination, port) with
163
173
| `Ipaddr ipaddr , Some port ->
164
- Lwt. return (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, port))
174
+ Lwt. return_ok (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, port))
165
175
| `Ipaddr ipaddr , None ->
166
- Lwt. return (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, 25 ))
176
+ Lwt. return_ok (Unix. ADDR_INET (Ipaddr_unix. to_inet_addr ipaddr, 25 ))
167
177
| `Domain_name domain_name , port ->
168
178
resolve (Domain_name. to_string domain_name) ?port " smtp" )
169
- >> = fun addr ->
179
+ >> ? fun addr ->
170
180
let socket =
171
181
Lwt_unix. socket (Unix. domain_of_sockaddr addr) Unix. SOCK_STREAM 0 in
172
- Lwt_unix. connect socket addr >> = fun () ->
182
+ connect socket addr >> ? fun () ->
173
183
let mail () = Lwt_scheduler. inj (mail () ) in
174
184
let ic = Lwt_io. of_fd ~mode: Lwt_io. Input socket in
175
185
let oc = Lwt_io. of_fd ~mode: Lwt_io. Output socket in
176
- match
177
- Option. map
178
- (fun authenticator -> Tls.Config. client ~authenticator () )
179
- authenticator
180
- with
181
- | Some (Error _ as err ) -> Lwt. return err
182
- | Some (Ok tls ) ->
183
- let ctx =
184
- Sendmail_with_starttls.Context_with_tls. make ?encoder ?decoder ?queue ()
185
- in
186
- Sendmail_with_starttls. sendmail lwt rdwr { ic; oc } ctx tls
187
- ?authentication ~domain sender recipients mail
188
- |> Lwt_scheduler. prj
189
- > |= open_sendmail_with_starttls_error
190
- | None ->
191
- let ctx = Colombe.State.Context. make ?encoder ?decoder () in
192
- Sendmail. sendmail lwt rdwr { ic; oc } ctx ~domain ?authentication sender
193
- recipients mail
194
- |> Lwt_scheduler. prj
195
- > |= open_sendmail_error
196
- > |= (function Error err -> Error (err :> error ) | Ok value -> Ok value)
197
- > |= open_error
186
+ Lwt. return (tls_config user's_tls_config user's_authenticator)
187
+ >> ? fun tls_cfg ->
188
+ let ctx =
189
+ Sendmail_with_starttls.Context_with_tls. make ?encoder ?decoder ?queue ()
190
+ in
191
+ Sendmail_with_starttls. sendmail lwt rdwr { ic; oc } ctx tls_cfg
192
+ ?authentication ~domain sender recipients mail
193
+ |> Lwt_scheduler. prj
194
+ > |= open_sendmail_with_starttls_error
0 commit comments