hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

Lazyman's job search

Last post 09-24-2006, 12:44 by Julien. 0 replies.
Sort Posts: Previous Next
  •  09-24-2006, 12:44 694

    Lazyman's job search

    Hi,

    this is a simple application to easily send CVs when the application is identical (except for the company). A form is displayed with information to fill in (which can be hard-coded as in the following example). The required information is basically email sending information + a resume + a cover letter + the recipient's details.

    The cover letter must actually a template. The script replaces <COMPANY> with the company name filled in the form. And <GENDER> by the appropriate "dear sir/ dear madam etc." specified in the form.

    Anyway, hopefully the script will make it clearer.



    (* ============ file Mailer.fs =========== *)
    module Mailer

        open System
        open System.Net.Mail
       
        type person = {first_name : string ; last_name: string ; email : string}
            with
               static member make f l e = {first_name = f ; last_name = l ; email = e}
            end
       
        let send_mail (client : #SmtpClient) sender subject body attachment_paths f dest =
            let sender = new MailAddress(sender.email, sender.first_name ^ sender.last_name) in
            let dest = new MailAddress(dest.email, dest.first_name ^ dest.last_name) in
            let email = new MailMessage(sender, dest) in
            email.ReplyTo <- sender ;
            email.Subject <- subject ;
            email.Body <- body ;
            attachment_paths |> List.iter (fun a -> email.Attachments.Add(new Attachment(a))) ;
            client.Send(email) ;
            match f with
                | Some f -> f dest subject body attachment_paths System.DateTime.Now
                | _ -> ()

        let send_mass_mail (client : #SmtpClient) sender subject body attachment_paths f dests =
            dests |> List.iter (send_mail client sender subject body attachment_paths f)

    (* ============ file Word.fs =========== *)
    module Word

        open System
        open System.Runtime.InteropServices
        open System.Reflection (* For Missing.Value *)
        open System.Collections
        open Microsoft.Office.Interop.Word

        let app = new ApplicationClass()
        let none = ref (box Missing.Value)

       
        (** Open a word document and return a handle to it. *)
        let open_file (file : string)  = app.Documents.Open(
            ref (box file),    //FileName
            none,   //ConfirmVersions
            none,   //ReadOnly
            none,   //AddToRecentFiles
            none,   //PasswordDocument
            none,   //PasswordTemplate
            none,   //Revert
            none,   //WritePasswordDocument
            none,   //WritePasswordTemplate
            none,   //Format
            none,   //Enconding
            none,   //Visible
            none,   //OpenAndRepair
            none,   //DocumentDirection
            none,   //NoEncodingDialog
            none,    //XMLTransform
            none    //NoAutoRepairDialog
            ) :?> DocumentClass
       
       
       
        let replace_word replace_all (to_replace : string) (to_replace_with : string) =
            let selection = app.ActiveWindow.Selection in
            try
                ignore (selection.Find.Execute(ref (box to_replace), // Text
                    none, // MatchCase
                    none, // MatchWholeWord
                    none, // MatchWildCards
                    none, // MatchSoundsLike
                    none, // MatchAllWordForms
                    none, // Forward
                    ref (box WdFindWrap.wdFindContinue), // Wrap
                    none, // Format
                    ref (box to_replace_with), // ReplaceWith
                    (if replace_all then ref (box WdReplace.wdReplaceAll) else  none), // Replace
                    none, // MatchKashida
                    none, // MatchDiatrics
                    none, // MatchAlefHamza
                    none, // MatchControl
                    none, // MatchPrefix
                    none, // MatchSuffic
                    none, // MatchPhrase
                    none, // IgnoreSpace
                    none)) // IgnorePunct
            with
                | e -> print_string e.Message 
                
               
        let save_as (doc : DocumentClass) name = doc.SaveAs(   
            ref (box name), //FileName
            none, // FileFormat
            none, // LockComments
            none, // PassWord    
            none, // AddToRecentFiles
            none, // WritePassword
            none, // ReadOnlyRecommended
            none, // EmbedTrueTypeFonts
            none, // SaveNativePictureFormat
            none, // SaveFormsData
            none, // SaveAsAOCELetter,
            none, // Encoding
            none, // InsertLineBreaks
            none, // AllowSubstitutions
            none, // LineEnding
            none  // AddBiDiMarks
            )   
     
        (* Show the application. Uncomment if you want to see the macro running. *)
        let make_app_visible b = app.Visible <- b
           
       
        let quit () =
            app.ActiveWindow.Close(ref (box WdSaveOptions.wdDoNotSaveChanges),none);
            app.Quit(none, none, none)

    (* ============ file ApplicationStrings.fs =========== *)

    module ApplicationStrings

        module Labels =
            begin
                let title = "Send your CV"
           
                let first_name = "First Name"
                let last_name = "Last Name"
                let e_mail = "E-Mail Address"
                let smtp_server = "SMTP Server"
                let login = "Login"
                let password = "Password"
               
                let resume = "Resume"
                let cover_letter = "Cover Letter"
                let browse = "Browse..."
                let attachment = "Attachment"
               
                let company = "Employer"
                let company_sector = "Sector"
                let employer_e_mail = "Employer E-mail"
                let gender = "Dear..."
                let genders = ["Dear Sir"; "Dear Madam"; "Dear Sir/Madam"]
                let body = "E-mail Body"
               
                let send = "Send"
                let cancel = "Cancel"
               
                let gender_in_cover_letter = "<GENDER>"           
                let company_in_cover_letter = "<COMPANY>"
               
                let subject s = "Job opportunities at " ^ s ^ " - Spontaneous application"
              
            end
           
        module DefaultValues =
            begin
                let first_name = "Julien"
                let last_name = ""
                let e_mail = "xyz@yahoo.fr"
                let smtp_server = "smtp.mail.yahoo.com"
                let login = "xyz"
                let password = "my_fantastic_unguessable_password"
                let resume = "C:\Documents and settings\Julien\Bureau\Candidacy\CV_Julien.doc"
                let cover_letter = "C:\Documents and settings\Julien\Bureau\Candidacy\coverLetter.doc"
                let company = ""
                let employer_e_mail = "recipient@company.com"
                let gender = "Dear Sir"
                let body = "E-mail Body"    
            end

    (* ============ file CVSenderForm.fs =========== *)

    module CVSenderForm

        open System
        open System.Drawing
        open System.Windows.Forms

        module L = ApplicationStrings.Labels

        (** Base form *)
        let form = new Form()
        do form.Text <- L.title
        do form.AutoSize <- true
        do form.AutoSizeMode <- AutoSizeMode.GrowAndShrink
        do form.Padding <- new Padding(5)
        do form.StartPosition <- FormStartPosition.CenterScreen

     

        (** Table layout that contains all elements *)
        let layout = new TableLayoutPanel ()
        let _ =
            layout.Dock <- DockStyle.Fill ;
            layout.AutoSize <- true ;
            layout.ColumnCount <- 3
           
           

        (** Helper function that adds a row to the table layout :
                - element one : label
                - element two : input
        *)

        let add_line (layout : TableLayoutPanel) sep (text : Label) (w : #Control) =
            let row = layout.RowCount + 1 in
            layout.RowCount <- row ;
           
            let sep_label = new Label() in
            sep_label.Text <- sep ;
           
            let f (c : #Control) = 
                c.AutoSize <- true ;
                c.Anchor <- Enum.combine [AnchorStyles.Top; AnchorStyles.Left; AnchorStyles.Bottom; ]
            in
            f sep_label;
            f text;
            f w ;
           
            sep_label.TextAlign <- ContentAlignment.MiddleLeft ;
           
            text.TextAlign <- ContentAlignment.MiddleLeft ;
            text.Click.Add( fun _ -> let _ = w.Focus() in () ) ;
           
            layout.Controls.Add(sep_label, 1, row) ;
            layout.Controls.Add(text, 0, row) ;
            layout.Controls.Add(w, 2, row)

        (** Settings Forms components *)

        let first_name = new TextBox()

        let first_name_label = new Label()
        do first_name_label.Text <- L.first_name
        do first_name_label.Click.Add (fun _ -> let _ = first_name.Focus() in () )

        do add_line layout ":" first_name_label first_name

        (* ---------------- *)  

        let last_name = new TextBox()

        let last_name_label = new Label()
        do last_name_label.Text <- L.last_name
        do last_name_label.Click.Add (fun _ -> let _ = last_name.Focus() in () )

        do add_line layout ":" last_name_label last_name

        (* ---------------- *)  

        let email = new TextBox()
           
        let email_label = new Label()
        do email_label.Text <- L.e_mail 
           
        do add_line layout ":" email_label email
           
        (* ---------------- *)

        let smtp_server = new TextBox()
        do smtp_server.Width <- 2 * smtp_server.Width
       

        let smtp_server_label = new Label()
        do smtp_server_label.Text <- L.smtp_server
        do smtp_server_label.Click.Add (fun _ -> let _ = smtp_server.Focus() in () )

        do add_line layout ":" smtp_server_label smtp_server

        (* ---------------- *)  

        let login = new TextBox()

        let login_label = new Label()
        do login_label.Text <- L.login
        do login_label.Click.Add (fun _ -> let _ = login.Focus() in () )

        do add_line layout ":" login_label login

        (* ---------------- *)

        let password = new TextBox()
        do password.PasswordChar <- '*'

        let password_label = new Label()
        do password_label.Text <- L.password
        do password_label.Click.Add (fun _ -> let _ = password.Focus() in () )

        do add_line layout ":" password_label password

        (* ---------------- *)

        let cv_panel = new FlowLayoutPanel()
        do cv_panel.Dock <- DockStyle.Fill
        do cv_panel.FlowDirection <- FlowDirection.LeftToRight
        do cv_panel.Margin <- new Padding(0)

        let cv = new TextBox()
        do cv.Width <- 2 * cv.Width

        let cv_button = new Button()
        do cv_button.Text <- L.browse
        do cv_button.Click.Add( fun _ ->
            let result = new OpenFileDialog() in
            result.InitialDirectory <- if cv.Text.Length >0 then cv.Text else "c:\\" ;
            if (result.ShowDialog() = DialogResult.OK) then
                cv.Text <- result.FileName
            )
        
        do cv_panel.Controls.Add(cv)   
        do cv_panel.Controls.Add(cv_button) 

        let cv_label = new Label()
        do cv_label.Text <- L.resume
        do cv_label.Click.Add (fun _ -> let _ = cv_button.Focus() in () )

        do add_line layout ":" cv_label cv_panel

        (* ---------------- *)  

        let cover_letter_panel = new FlowLayoutPanel()
        do cover_letter_panel.Dock <- DockStyle.Fill
        do cover_letter_panel.FlowDirection <- FlowDirection.LeftToRight
        do cover_letter_panel.Margin <- new Padding(0)

        let cover_letter = new TextBox()
        do cover_letter.Width <- 2 * cover_letter.Width
       
        let cover_letter_button = new Button()
        do cover_letter_button.Text <- L.browse 
        do cover_letter_button.Click.Add( fun _ ->
            let result = new OpenFileDialog() in
            result.InitialDirectory <- if cover_letter.Text.Length >0 then cover_letter.Text else "c:\\" ;
            if (result.ShowDialog() = DialogResult.OK) then
                cover_letter.Text <- result.FileName
            )
        
        do cover_letter_panel.Controls.Add(cover_letter)
        do cover_letter_panel.Controls.Add(cover_letter_button)   

        let cover_letter_label = new Label()
        do cover_letter_label.Text <- L.cover_letter
        do cover_letter_label.Click.Add (fun _ -> let _ = cover_letter_button.Focus() in () )

        do add_line layout ":" cover_letter_label cover_letter_panel

        (* ---------------- *)

        let company = new TextBox()
           
        let company_label = new Label()
        do company_label.Text <- L.company
           
        do add_line layout ":" company_label company

        (* ---------------- *)

        let dest = new TextBox()
           
        let dest_label = new Label()
        do dest_label.Text <- L.employer_e_mail
           
        do add_line layout ":" dest_label dest

        (* ---------------- *)

        let gender = new ComboBox()
        do L.genders |> List.iter (fun g -> ignore (gender.Items.Add (g)) ) 
        do gender.SelectedIndex <- 0
           
        let gender_label = new Label()
        do gender_label.Text <- L.gender
           
        do add_line layout ":" gender_label gender

        (* ---------------- *)

        let email_body = new TextBox()
        do email_body.Multiline <- true
        do email_body.WordWrap <- true
        do email_body.ScrollBars <- ScrollBars.Vertical
        do email_body.Width <- 3 * email_body.Width
        do email_body.Height <- 5 * email_body.Height
       
       
        let email_body_label = new Label()
        do email_body_label.Text <- L.body
           
        do add_line layout ":" email_body_label email_body 
              
        (* ---------------- *)  

        let validation_panel = new FlowLayoutPanel()
        do validation_panel.Dock <- DockStyle.Fill
        do validation_panel.FlowDirection <- FlowDirection.LeftToRight
        do validation_panel.Margin <- new Padding(0)

        let ok = new Button()
        do ok.Text <- L.send 

        let cancel = new Button()
        do cancel.Text <- L.cancel
        do cancel.Click.Add(fun _ -> form.Close())
        
        do validation_panel.Controls.Add(ok)
        do validation_panel.Controls.Add(cancel)
           
        do add_line layout " " (new Label()) validation_panel

        (* ---------------- *)   
        do form.Controls.Add(layout)

    (* ============ file main.fs =========== *)

    open System
    open System.Net.Mail
    open System.Windows.Forms

    open CVSenderForm

    module L = ApplicationStrings.Labels
    module DV = ApplicationStrings.DefaultValues

    let new_cover_letter () =   
        let path = cover_letter.Text in
        let path = path.Replace("\\", "\\\\") in
        let doc = Word.open_file path in
       
        let replace_words lst = lst |> List.iter (fun (before, after) -> Word.replace_word true before after) in
       
        let words =
            (L.gender_in_cover_letter, gender.Text) ::
            (L.company_in_cover_letter, company.Text) ::
            []
        in words |> replace_words ;
       
        let path_parts = path.Split([|'.'|], 2) in
        let before, after = path_parts.(0), path_parts.(1) in
        let new_path = before :: ("_" ^ company.Text.Replace(" ","") ^ ".") :: after :: [] |> String.concat "" in
        Word.save_as doc new_path ;            
        Word.quit() ;
        new_path

     

    (* ================================================================ *)

    let send_job_application () =
        (** Check *)
        let debug s = Console.WriteLine(s ^ "\n") in
       
        (** Make sure everything's filled *)
        if first_name.Text.Length = 0
            || last_name.Text.Length = 0
            || email.Text.Length = 0
            || login.Text.Length = 0
            || password.Text.Length = 0
            || cv.Text.Length = 0
            || cover_letter.Text.Length = 0
            || smtp_server.Text.Length = 0
            || company.Text.Length = 0
            || dest.Text.Length = 0
            || email_body.Text.Length = 0
            then begin
                debug "Make sure all fields are filled, and that attachments refer to files and not directories.";
                failwith ""
            end ;

        (** Prepare the mail info *)
        let login = login.Text in
        let password = password.Text in
        let server = smtp_server.Text in   
        let client = new SmtpClient(server) in
        client.Credentials <- new System.Net.NetworkCredential(login, password) ;

        (** Process the attachments *)
        let cover_letter_path = new_cover_letter() in
        let cv_path = cv.Text.Replace("\\", "<A>\\\\</A>") in
        let attachments = cv_path :: cover_letter_path :: [] in
       
        (** Sender *)
        let me = Mailer.person.make first_name.Text last_name.Text email.Text in  
       
       
        (** Mail content *)
        let subject = L.subject company.Text in
        let body = gender.Text ^ "," ^Environment.NewLine ^ Environment.NewLine ^ email_body.Text in
        let dest = Mailer.person.make "" "" dest.Text in   
       
        (** Send the mail *)
        try
            debug ("********************************************************************");
            debug ("Sender : " ^ any_to_string me) ;
            debug ("Login : " ^ login) ;
            debug ("Password : " ^ password) ;
            debug ("Dest : " ^ any_to_string dest) ;
            debug ("Server : " ^ any_to_string client) ;
            attachments |> List.iter (fun a -> debug ("Attachment : " ^ a)) ;
            debug ("Subject : " ^ subject) ;
            debug ("Body : " ^ body) ;   
            Mailer.send_mail client me subject body attachments None dest ;
            debug ("===================================");
            debug ("= MAIL SENT");
            debug ("===================================");
            debug ("********************************************************************");
        with e ->
            begin
                debug e.Message ;
                debug ("********************************************************************");
                raise e
            end

    (* ================================================================ *)

    (** Fill the form with the default settings *)
    let prepare_form () =
        first_name.Text <- DV.first_name;
        last_name.Text <- DV.last_name;
        email.Text <- DV.e_mail ;
        smtp_server.Text <- DV.smtp_server;
        login.Text <- DV.login;
        password.Text <- DV.password;
        cv.Text <- DV.resume;
        cover_letter.Text <- DV.cover_letter;
        company.Text <- DV.company ;
        dest.Text <- DV.employer_e_mail ;
        email_body.Text <- DV.body
       

    (* ================================================================ *)   
       
    [<STAThread>]   
    let _ =
        Application.EnableVisualStyles () ;   
        prepare_form() ;
        ok.Click.Add(fun e -> try send_job_application() with _ -> ignore(MessageBox.Show("Failure sending the email. See the console.")) ) ;   
        Application.Run(form)

    Of course, this can very easily be adapted to send emails to whatever recipient source that you have.

    Notes :
     - you need the Microsoft.Office.Interop.Word.dll file
     - need the .Net Framework 2.0 (and so do the people using it)
     - using smtp.mail.free_provider.com will fail with some internet access providers, so replace it with your actual access provider if you can...
    - example cover_letter.doc : <GENDER>, I reaaaaaally love <COMPANY>, so pleassssse, hire me. I'll do everything I can to make <COMPANY> richer and happier. So once again, hire me, please!

View as RSS news feed in XML
Powered by Community Server, by Telligent Systems