title: Valid URL for an FTP site with username containing @
body: <p>I want to create a valid URL to send to Windows File Explorer (or other file managers like TotalCommander) using the format:</p>
  
  <pre><code>ftp://username:password@ftp.domain.ext/folder/
  </code></pre>
  
  <p>In Explorer, it works with very straight username and password. But I receive errors (or Explorer just display the My Document instead of the FTP site) when password contains certain special characters. I played with URI encoding to encode the password with some success but not 100% reliable.</p>
  
  <p>Can someone help me finding the correct requirements for a valid FTP URL including username and password? Thanks.</p>
  
  <p>Here is a sample of the code using AutoHotkey "Run" command (on Windows 7 64-bit environment):</p>
  
  <pre><code>#NoEnv
  #SingleInstance force
  
  strFTPUrl := "ftp://www.jeanlalonde.ca"
  
  strLoginName := "username@jeanlalonde.ca"
  strPassword := "********"
  
  StringReplace, strFTPUrl, strFTPUrl, % "ftp://", % "ftp://" . strLoginName . ":" . UriEncode(strPassword) . "@"
  
  ; Before: ftp://ftp.jeanlalonde.ca
  ; After: ftp://testaccount@jeanlalonde.ca:********@ftp.jeanlalonde.ca
  MsgBox, %strFTPUrl%
  
  Run, Explorer "%strFTPUrl%"
  
  return
  
  
  ;------------------------------------------------------------
  UriEncode(str)
  ; from GoogleTranslate by Mikhail Kuropyatnikov
  ; http://www.autohotkey.net/~sumon/GoogleTranslate.ahk
  ;------------------------------------------------------------
  { 
     b_Format := A_FormatInteger 
     data := "" 
     SetFormat,Integer,H 
     SizeInBytes := StrPutVar(str,var,"utf-8")
     Loop, %SizeInBytes%
     {
     ch := NumGet(var,A_Index-1,"UChar")
     If (ch=0)
        Break
     if ((ch&gt;0x7f) || (ch&lt;0x30) || (ch=0x3d))
        s .= "%" . ((StrLen(c:=SubStr(ch,3))&lt;2) ? "0" . c : c)
     Else
        s .= Chr(ch)
     }   
     SetFormat,Integer,%b_format% 
     return s 
  } 
  ;------------------------------------------------------------
  
  
  ;------------------------------------------------------------
  StrPutVar(string, ByRef var, encoding)
  ;------------------------------------------------------------
  {
      ; Ensure capacity.
      SizeInBytes := VarSetCapacity( var, StrPut(string, encoding)
          ; StrPut returns char count, but VarSetCapacity needs bytes.
          * ((encoding="utf-16"||encoding="cp1200") ? 2 : 1) )
      ; Copy or convert the string.
      StrPut(string, &amp;var, encoding)
     Return SizeInBytes 
  }
  ;------------------------------------------------------------
  </code></pre>