15 people like it.

Async SMTP

Async wrapper for SmtpClient (which is event-based)

 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: 
open System
open System.Net
open System.Net.Mail
open System.Threading

/// from http://msdn.microsoft.com/en-us/magazine/cc163467.aspx
type internal AsyncResultNoResult(callback: AsyncCallback, state: obj) = 
    let statePending = 0
    let stateCompletedSync = 1
    let stateCompletedAsync = 2
    let mutable completedState = statePending
    let mutable waitHandle: ManualResetEvent = null
    let mutable resultException: exn = null
    interface IAsyncResult with
        member x.AsyncState = state
        member x.AsyncWaitHandle = 
            if waitHandle = null then
                let isDone = (x :> IAsyncResult).IsCompleted
                let mre = new ManualResetEvent(isDone)
                if Interlocked.CompareExchange(&waitHandle, mre, null) <> null
                    then mre.Close()
                    else
                        if not isDone && (x :> IAsyncResult).IsCompleted
                            then waitHandle.Set() |> ignore
            upcast waitHandle
        member x.CompletedSynchronously = 
            Thread.VolatileRead(&completedState) = stateCompletedSync
        member x.IsCompleted = 
            Thread.VolatileRead(&completedState) <> statePending
    member x.SetAsCompleted(e: exn, completedSynchronously: bool) = 
        resultException <- e
        let prevState = Interlocked.Exchange(&completedState, if completedSynchronously then stateCompletedSync else stateCompletedAsync)
        if prevState <> statePending
            then raise <| InvalidOperationException("You can set a result only once")
        if waitHandle <> null
            then waitHandle.Set() |> ignore
        if callback <> null
            then callback.Invoke(x)
    member x.EndInvoke() = 
        let this = x :> IAsyncResult
        if not this.IsCompleted then
            this.AsyncWaitHandle.WaitOne() |> ignore
            this.AsyncWaitHandle.Close()
            waitHandle <- null
        if resultException <> null
            then raise resultException

type SmtpClient with
    member private x.GetAsyncResult(callback, state) : IAsyncResult = 
        let r = AsyncResultNoResult(callback, state)
        x.SendCompleted
        |> Event.add(fun args -> r.SetAsCompleted(args.Error, false))
        upcast r
        
    member x.BeginSend(message: MailMessage, callback, state) = 
        let r = x.GetAsyncResult(callback, state)
        x.SendAsync(message, null)
        r

    member x.BeginSend(from, recipients, subject, body, callback, state) = 
        let r = x.GetAsyncResult(callback, state)
        x.SendAsync(from, recipients, subject, body, null)
        r

    member x.EndSend(result: IAsyncResult) = 
        let result = result :?> AsyncResultNoResult
        result.EndInvoke()

    member x.AsyncSend(message: MailMessage) = 
        Async.FromBeginEnd((fun(iar,state) -> x.BeginSend(message, iar, state)), x.EndSend, x.SendAsyncCancel)

    member x.AsyncSend(from, recipients, subject, body) : Async<unit> = 
        Async.FromBeginEnd((fun(iar,state) -> x.BeginSend(from, recipients, subject, body, iar, state)), x.EndSend, x.SendAsyncCancel)

(*
// silly example
async { 
    let credentials = NetworkCredential("you@gmail.com", "yourpassword")
    use smtp = new SmtpClient("smtp.gmail.com", 587, EnableSsl = true, Credentials = credentials)
    do! smtp.AsyncSend("you@gmail.com", "your.email@gmail.com", "this subject", "cucamonga")
} |> Async.RunSynchronously
*)
namespace System
namespace System.Net
namespace System.Net.Mail
namespace System.Threading
Multiple items
type internal AsyncResultNoResult =
  interface IAsyncResult
  new : callback:AsyncCallback * state:obj -> AsyncResultNoResult
  member EndInvoke : unit -> unit
  member SetAsCompleted : e:exn * completedSynchronously:bool -> unit

Full name: Script.AsyncResultNoResult


 from http://msdn.microsoft.com/en-us/magazine/cc163467.aspx


--------------------
internal new : callback:AsyncCallback * state:obj -> AsyncResultNoResult
val callback : AsyncCallback
type AsyncCallback =
  delegate of IAsyncResult -> unit

Full name: System.AsyncCallback
val state : obj
type obj = Object

Full name: Microsoft.FSharp.Core.obj
val statePending : int
val stateCompletedSync : int
val stateCompletedAsync : int
val mutable completedState : int
val mutable waitHandle : ManualResetEvent
Multiple items
type ManualResetEvent =
  inherit EventWaitHandle
  new : initialState:bool -> ManualResetEvent

Full name: System.Threading.ManualResetEvent

--------------------
ManualResetEvent(initialState: bool) : unit
val mutable resultException : exn
type exn = Exception

Full name: Microsoft.FSharp.Core.exn
type IAsyncResult =
  member AsyncState : obj
  member AsyncWaitHandle : WaitHandle
  member CompletedSynchronously : bool
  member IsCompleted : bool

Full name: System.IAsyncResult
val x : AsyncResultNoResult
override internal AsyncResultNoResult.AsyncState : obj

Full name: Script.AsyncResultNoResult.AsyncState
override internal AsyncResultNoResult.AsyncWaitHandle : WaitHandle

Full name: Script.AsyncResultNoResult.AsyncWaitHandle
val isDone : bool
val mre : ManualResetEvent
type Interlocked =
  static member Add : location1:int * value:int -> int + 1 overload
  static member CompareExchange : location1:int * value:int * comparand:int -> int + 6 overloads
  static member Decrement : location:int -> int + 1 overload
  static member Exchange : location1:int * value:int -> int + 6 overloads
  static member Increment : location:int -> int + 1 overload
  static member Read : location:int64 -> int64

Full name: System.Threading.Interlocked
Interlocked.CompareExchange<'T (requires reference type)>(location1: byref<'T>, value: 'T, comparand: 'T) : 'T
Interlocked.CompareExchange(location1: byref<nativeint>, value: nativeint, comparand: nativeint) : nativeint
Interlocked.CompareExchange(location1: byref<obj>, value: obj, comparand: obj) : obj
Interlocked.CompareExchange(location1: byref<float>, value: float, comparand: float) : float
Interlocked.CompareExchange(location1: byref<float32>, value: float32, comparand: float32) : float32
Interlocked.CompareExchange(location1: byref<int64>, value: int64, comparand: int64) : int64
Interlocked.CompareExchange(location1: byref<int>, value: int, comparand: int) : int
WaitHandle.Close() : unit
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
EventWaitHandle.Set() : bool
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
override internal AsyncResultNoResult.CompletedSynchronously : bool

Full name: Script.AsyncResultNoResult.CompletedSynchronously
Multiple items
type Thread =
  inherit CriticalFinalizerObject
  new : start:ThreadStart -> Thread + 3 overloads
  member Abort : unit -> unit + 1 overload
  member ApartmentState : ApartmentState with get, set
  member CurrentCulture : CultureInfo with get, set
  member CurrentUICulture : CultureInfo with get, set
  member DisableComObjectEagerCleanup : unit -> unit
  member ExecutionContext : ExecutionContext
  member GetApartmentState : unit -> ApartmentState
  member GetCompressedStack : unit -> CompressedStack
  member GetHashCode : unit -> int
  ...

Full name: System.Threading.Thread

--------------------
Thread(start: ThreadStart) : unit
Thread(start: ParameterizedThreadStart) : unit
Thread(start: ThreadStart, maxStackSize: int) : unit
Thread(start: ParameterizedThreadStart, maxStackSize: int) : unit
Thread.VolatileRead(address: byref<obj>) : obj
   (+0 other overloads)
Thread.VolatileRead(address: byref<float>) : float
   (+0 other overloads)
Thread.VolatileRead(address: byref<float32>) : float32
   (+0 other overloads)
Thread.VolatileRead(address: byref<uint64>) : uint64
   (+0 other overloads)
Thread.VolatileRead(address: byref<unativeint>) : unativeint
   (+0 other overloads)
Thread.VolatileRead(address: byref<nativeint>) : nativeint
   (+0 other overloads)
Thread.VolatileRead(address: byref<uint32>) : uint32
   (+0 other overloads)
Thread.VolatileRead(address: byref<uint16>) : uint16
   (+0 other overloads)
Thread.VolatileRead(address: byref<sbyte>) : sbyte
   (+0 other overloads)
Thread.VolatileRead(address: byref<int64>) : int64
   (+0 other overloads)
override internal AsyncResultNoResult.IsCompleted : bool

Full name: Script.AsyncResultNoResult.IsCompleted
member internal AsyncResultNoResult.SetAsCompleted : e:exn * completedSynchronously:bool -> unit

Full name: Script.AsyncResultNoResult.SetAsCompleted
val e : exn
val completedSynchronously : bool
type bool = Boolean

Full name: Microsoft.FSharp.Core.bool
val prevState : int
Interlocked.Exchange<'T (requires reference type)>(location1: byref<'T>, value: 'T) : 'T
Interlocked.Exchange(location1: byref<nativeint>, value: nativeint) : nativeint
Interlocked.Exchange(location1: byref<obj>, value: obj) : obj
Interlocked.Exchange(location1: byref<float>, value: float) : float
Interlocked.Exchange(location1: byref<float32>, value: float32) : float32
Interlocked.Exchange(location1: byref<int64>, value: int64) : int64
Interlocked.Exchange(location1: byref<int>, value: int) : int
val raise : exn:Exception -> 'T

Full name: Microsoft.FSharp.Core.Operators.raise
Multiple items
type InvalidOperationException =
  inherit SystemException
  new : unit -> InvalidOperationException + 2 overloads

Full name: System.InvalidOperationException

--------------------
InvalidOperationException() : unit
InvalidOperationException(message: string) : unit
InvalidOperationException(message: string, innerException: exn) : unit
AsyncCallback.Invoke(ar: IAsyncResult) : unit
member internal AsyncResultNoResult.EndInvoke : unit -> unit

Full name: Script.AsyncResultNoResult.EndInvoke
val this : IAsyncResult
property IAsyncResult.IsCompleted: bool
property IAsyncResult.AsyncWaitHandle: WaitHandle
WaitHandle.WaitOne() : bool
WaitHandle.WaitOne(timeout: TimeSpan) : bool
WaitHandle.WaitOne(millisecondsTimeout: int) : bool
WaitHandle.WaitOne(timeout: TimeSpan, exitContext: bool) : bool
WaitHandle.WaitOne(millisecondsTimeout: int, exitContext: bool) : bool
Multiple items
type SmtpClient =
  new : unit -> SmtpClient + 2 overloads
  member ClientCertificates : X509CertificateCollection
  member Credentials : ICredentialsByHost with get, set
  member DeliveryMethod : SmtpDeliveryMethod with get, set
  member Dispose : unit -> unit
  member EnableSsl : bool with get, set
  member Host : string with get, set
  member PickupDirectoryLocation : string with get, set
  member Port : int with get, set
  member Send : message:MailMessage -> unit + 1 overload
  ...

Full name: System.Net.Mail.SmtpClient

--------------------
SmtpClient() : unit
SmtpClient(host: string) : unit
SmtpClient(host: string, port: int) : unit
val x : SmtpClient
member private SmtpClient.GetAsyncResult : callback:AsyncCallback * state:'a -> IAsyncResult

Full name: Script.GetAsyncResult
val state : 'a
val r : AsyncResultNoResult
event SmtpClient.SendCompleted: IEvent<SendCompletedEventHandler,ComponentModel.AsyncCompletedEventArgs>
Multiple items
module Event

from Microsoft.FSharp.Control

--------------------
type Event<'T> =
  new : unit -> Event<'T>
  member Trigger : arg:'T -> unit
  member Publish : IEvent<'T>

Full name: Microsoft.FSharp.Control.Event<_>

--------------------
type Event<'Delegate,'Args (requires delegate and 'Delegate :> Delegate)> =
  new : unit -> Event<'Delegate,'Args>
  member Trigger : sender:obj * args:'Args -> unit
  member Publish : IEvent<'Delegate,'Args>

Full name: Microsoft.FSharp.Control.Event<_,_>

--------------------
new : unit -> Event<'T>

--------------------
new : unit -> Event<'Delegate,'Args>
val add : callback:('T -> unit) -> sourceEvent:IEvent<'Del,'T> -> unit (requires delegate and 'Del :> Delegate)

Full name: Microsoft.FSharp.Control.Event.add
val args : ComponentModel.AsyncCompletedEventArgs
member internal AsyncResultNoResult.SetAsCompleted : e:exn * completedSynchronously:bool -> unit
property ComponentModel.AsyncCompletedEventArgs.Error: exn
member SmtpClient.BeginSend : message:MailMessage * callback:AsyncCallback * state:'a -> IAsyncResult

Full name: Script.BeginSend
val message : MailMessage
Multiple items
type MailMessage =
  new : unit -> MailMessage + 3 overloads
  member AlternateViews : AlternateViewCollection
  member Attachments : AttachmentCollection
  member Bcc : MailAddressCollection
  member Body : string with get, set
  member BodyEncoding : Encoding with get, set
  member CC : MailAddressCollection
  member DeliveryNotificationOptions : DeliveryNotificationOptions with get, set
  member Dispose : unit -> unit
  member From : MailAddress with get, set
  ...

Full name: System.Net.Mail.MailMessage

--------------------
MailMessage() : unit
MailMessage(from: string, to: string) : unit
MailMessage(from: MailAddress, to: MailAddress) : unit
MailMessage(from: string, to: string, subject: string, body: string) : unit
val r : IAsyncResult
member private SmtpClient.GetAsyncResult : callback:AsyncCallback * state:'a -> IAsyncResult
SmtpClient.SendAsync(message: MailMessage, userToken: obj) : unit
SmtpClient.SendAsync(from: string, recipients: string, subject: string, body: string, userToken: obj) : unit
member SmtpClient.BeginSend : from:string * recipients:string * subject:string * body:string * callback:AsyncCallback * state:'a -> IAsyncResult

Full name: Script.BeginSend
val from : string
val recipients : string
val subject : string
val body : string
member SmtpClient.EndSend : result:IAsyncResult -> unit

Full name: Script.EndSend
val result : IAsyncResult
val result : AsyncResultNoResult
member internal AsyncResultNoResult.EndInvoke : unit -> unit
member SmtpClient.AsyncSend : message:MailMessage -> Async<unit>

Full name: Script.AsyncSend
Multiple items
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
static member Async.FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member Async.FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member Async.FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member Async.FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
val iar : AsyncCallback
member SmtpClient.BeginSend : message:MailMessage * callback:AsyncCallback * state:'a -> IAsyncResult
member SmtpClient.BeginSend : from:string * recipients:string * subject:string * body:string * callback:AsyncCallback * state:'a -> IAsyncResult
member SmtpClient.EndSend : result:IAsyncResult -> unit
SmtpClient.SendAsyncCancel() : unit
member SmtpClient.AsyncSend : from:string * recipients:string * subject:string * body:string -> Async<unit>

Full name: Script.AsyncSend
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
Raw view Test code New version

More information

Link:http://fssnip.net/1C
Posted:13 years ago
Author:Mauricio Scheffer
Tags: async , smtp