package sendmail-lwt
Implementation of the sendmail command over LWT
Install
Dune Dependency
Authors
Maintainers
Sources
colombe-0.10.0.tbz
sha256=065ecfe82e867f4f8b267c5fcb7e9dd8fef424601b10bc731f5f2012fde81bda
sha512=7ed60b73420ab7a3950f9d0fe7b5d05d18eff48080cce1869adfd601c71a06ee01f818a0010e2c38b30d45305c99765339917123ff300ca0de375263c2ef544a
doc/src/sendmail-lwt/sendmail_lwt.ml.html
Source file sendmail_lwt.ml
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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
open Lwt.Infix open Colombe let ( <.> ) f g x = f (g x) let ( >>? ) = Lwt_result.bind let error_msgf fmt = Fmt.kstr (fun msg -> Error (`Msg msg)) fmt module Lwt_scheduler = Sigs.Make (Lwt) let lwt_bind x f = let open Lwt.Infix in let open Lwt_scheduler in inj (prj x >>= (prj <.> f)) let lwt = { Sigs.bind = lwt_bind; return = (fun x -> Lwt_scheduler.inj (Lwt.return x)) } type flow = { ic : Lwt_io.input_channel; oc : Lwt_io.output_channel } let rdwr = { Sigs.rd = (fun { ic; _ } bytes off len -> let open Lwt.Infix in Lwt_scheduler.inj (Lwt_io.read_into ic bytes off len >>= function | 0 -> Lwt.return `End | len -> Lwt.return (`Len len))); wr = (fun { oc; _ } bytes off len -> let res = Lwt_io.write_from_exactly oc (Bytes.unsafe_of_string bytes) off len in Lwt_scheduler.inj res); } type destination = [ `Ipaddr of Ipaddr.t | `Domain_name of [ `host ] Domain_name.t ] type error = [ `Msg of string | Sendmail_with_starttls.error ] let open_sendmail_error = function | Ok _ as v -> v | Error (#Sendmail.error as err) -> Error err let open_sendmail_with_starttls_error = function | Ok _ as v -> v | Error (#Sendmail_with_starttls.error as err) -> Error err let open_error = function Ok _ as v -> v | Error (#error as err) -> Error err let authenticator = Lazy.from_fun Ca_certs.authenticator let tls_config user's_tls_config user's_authenticator = match user's_tls_config with | Some cfg -> Ok cfg | None -> let ( let* ) = Result.bind in let* authenticator = match (Lazy.force authenticator, user's_authenticator) with | Ok authenticator, None -> Ok authenticator | _, Some authenticator -> Ok authenticator | (Error _ as err), None -> err in Tls.Config.client ~authenticator () let resolve host ?port service = Lwt_unix.getprotobyname "tcp" >>= fun tcp -> Lwt_unix.getaddrinfo host service Unix.[ AI_PROTOCOL tcp.Unix.p_proto ] >>= fun result -> match (result, port) with | [], None -> Lwt.return (error_msgf "Service %S is not recognized by your system or the host %s is \ unreachable" service host) | [], Some port -> ( Lwt_unix.gethostbyname host >>= function | { Unix.h_addr_list = [||]; _ } -> Lwt.return (error_msgf "Host %s unreachable" host) | { Unix.h_addr_list; _ } -> Lwt.return_ok (Unix.ADDR_INET (h_addr_list.(0), port))) | ai :: _, _ -> match (port, ai.ai_addr) with | Some port, Unix.ADDR_INET (inet_addr, _) -> Lwt.return_ok (Unix.ADDR_INET (inet_addr, port)) | _ -> Lwt.return_ok ai.ai_addr let pp_addr ppf = function | Unix.ADDR_INET (inet_addr, port) -> Fmt.pf ppf "%s:%d" (Unix.string_of_inet_addr inet_addr) port | Unix.ADDR_UNIX str -> Fmt.pf ppf "<%s>" str let connect socket addr = Lwt.pick [ Lwt_unix.sleep 5.0 >|= Fun.const `Timeout; Lwt_unix.connect socket addr >|= Fun.const `Connected; ] >>= function | `Timeout -> Lwt.return (error_msgf "Connection to %a timeout" pp_addr addr) | `Connected -> Lwt.return_ok () let submit ?encoder ?decoder ?queue ~destination ?port ~domain ?cfg:user's_tls_config ?authenticator:user's_authenticator ?authentication sender recipients mail = let mail () = Lwt_scheduler.inj (mail ()) in Lwt.return (tls_config user's_tls_config user's_authenticator) >>? fun tls_cfg -> let protocol = match port with | Some 587 -> `With_starttls tls_cfg | Some _ | None -> `With_tls tls_cfg in match protocol with | `With_starttls tls -> (match (destination, port) with | `Ipaddr ipaddr, Some port -> Lwt.return_ok (Unix.ADDR_INET (Ipaddr_unix.to_inet_addr ipaddr, port)) | `Ipaddr ipaddr, None -> Lwt.return_ok (Unix.ADDR_INET (Ipaddr_unix.to_inet_addr ipaddr, 587)) | `Domain_name domain_name, port -> resolve (Domain_name.to_string domain_name) ?port "submission") >>? fun addr -> let socket = Lwt_unix.socket (Unix.domain_of_sockaddr addr) Unix.SOCK_STREAM 0 in connect socket addr >>? fun () -> let ic = Lwt_io.of_fd ~mode:Lwt_io.Input socket in let oc = Lwt_io.of_fd ~mode:Lwt_io.Output socket in let ctx = Sendmail_with_starttls.Context_with_tls.make ?encoder ?decoder ?queue () in Sendmail_with_starttls.sendmail lwt rdwr { ic; oc } ctx tls ?authentication ~domain sender recipients mail |> Lwt_scheduler.prj >|= open_sendmail_with_starttls_error >|= open_error | `With_tls tls -> (match (destination, port) with | `Ipaddr ipaddr, Some port -> let addr = Unix.ADDR_INET (Ipaddr_unix.to_inet_addr ipaddr, port) in let socket = Lwt_unix.socket (Unix.domain_of_sockaddr addr) Unix.SOCK_STREAM 0 in connect socket addr >>? fun () -> Tls_lwt.Unix.client_of_fd tls socket >|= Tls_lwt.of_t ~close:(fun () -> Lwt_unix.close socket) >|= Result.ok | `Ipaddr ipaddr, None -> let addr = Unix.ADDR_INET (Ipaddr_unix.to_inet_addr ipaddr, 465) in let socket = Lwt_unix.socket (Unix.domain_of_sockaddr addr) Unix.SOCK_STREAM 0 in connect socket addr >>? fun () -> Tls_lwt.Unix.client_of_fd tls socket >|= Tls_lwt.of_t ~close:(fun () -> Lwt_unix.close socket) >|= Result.ok | `Domain_name domain_name, port -> let port = Option.value ~default:465 port in Tls_lwt.connect_ext tls (Domain_name.to_string domain_name, port) >|= Result.ok) >>? fun (ic, oc) -> let ctx = Colombe.State.Context.make ?encoder ?decoder () in Sendmail.sendmail lwt rdwr { ic; oc } ctx ~domain ?authentication sender recipients mail |> Lwt_scheduler.prj >|= open_sendmail_error >|= (function Error err -> Error (err :> error) | Ok value -> Ok value) >|= open_error let sendmail ?encoder ?decoder ?queue ~destination ?port ~domain ?cfg:user's_tls_config ?authenticator:user's_authenticator ?authentication sender recipients mail = (match (destination, port) with | `Ipaddr ipaddr, Some port -> Lwt.return_ok (Unix.ADDR_INET (Ipaddr_unix.to_inet_addr ipaddr, port)) | `Ipaddr ipaddr, None -> Lwt.return_ok (Unix.ADDR_INET (Ipaddr_unix.to_inet_addr ipaddr, 25)) | `Domain_name domain_name, port -> resolve (Domain_name.to_string domain_name) ?port "smtp") >>? fun addr -> let socket = Lwt_unix.socket (Unix.domain_of_sockaddr addr) Unix.SOCK_STREAM 0 in connect socket addr >>? fun () -> let mail () = Lwt_scheduler.inj (mail ()) in let ic = Lwt_io.of_fd ~mode:Lwt_io.Input socket in let oc = Lwt_io.of_fd ~mode:Lwt_io.Output socket in Lwt.return (tls_config user's_tls_config user's_authenticator) >>? fun tls_cfg -> let ctx = Sendmail_with_starttls.Context_with_tls.make ?encoder ?decoder ?queue () in Sendmail_with_starttls.sendmail lwt rdwr { ic; oc } ctx tls_cfg ?authentication ~domain sender recipients mail |> Lwt_scheduler.prj >|= open_sendmail_with_starttls_error
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>