به نام خدا

در پارسي‌بلاگسامان دهي ايميل با گو

جمعه ۱۹ دي ۱۳۹۳ - ۲:۳۱ عصر

بالاخره تمام شد
چند روز وقت گرفت
تمام اوقات فراغت اين چند روز را كار كردم
اولين برنامه‌ام به زبان Go

احتمالاً شما نيز گرفتار دستيابي به ايميل‌هاي قديمي خود شده‌ايد
ايميل‌هايي كه از سال‌ها پيش بايگاني شده‌اند
از روزهايي كه با Outlook كار مي‌كرديم
تا سرويس‌هاي مختلف تحت وب
همه را در فايل‌هاي eml نگهداشته بودم
و هر بار كه دنبال ايميلي مي‌گشتم
زمان زيادي از دست مي‌رفت

تصميم گرفتم يك برنامه بنويسم
كه تمام ده هزار فايل موجود را دسته‌بندي كند
بر اساس ايميل فرستنده و گيرنده

زبان Go را گفتند خيلي سريع است
چند سالي‌ست كه گوگل توسعه آن را آغاز كرده
جايي خواندم كه ده برابر سريع‌تر از زبان‌هاي موجود

بسيار شبيه C و جاوا بود
تصميم گرفتم تجربه كنم
خيلي دستورها را خلاصه كرده
و علامت‌‌هاي اضافي و بي‌كاربرد را پيراسته
قابليت‌هاي جديدي نيز افزوده
جالب‌ترين امكانش
بازگرداندن چندين مقدار از يك تابع، تنها با يك دستور بازگشت (!)

اگر چه ابزاري‌ست كه بيشتر براي نوشتن Crawlerها
و ابزارهاي سروري استفاده مي‌شود
ولي من در اولين تجربه خود
اين ابزار را با آن نوشتم
(نسخه غير فشرده)

كار كردن با آن آسان است
كافيست در پوشه‌اي قرار دهيد
كه تمام فايل‌هاي eml در آن قرار دارد
همه در يك پوشه باشند
برنامه را كه اجرا كنيد
براي هر نشاني و آدرس يك پوشه مي‌سازد
و تمام ايميل‌هاي مربوط به آن نشاني را
در همان پوشه
بر اساس تاريخ قرار مي‌دهد
نام فايل‌ها را به تاريخ و ساعت
كه دسترسي آسان باشد
يك علامت R يا S هم در انتها
تا معلوم شود ارسالي‌ست يا دريافتي
و تمام

واقعاً سريع عمل كرد
من دقيقاً 10024 عدد فايل eml داشتم
از سال 2000 تا كنون
با حجم حدود 5 گيگابايت
از ياهو و جيميل و هات‌ميل هم در آن بود
و از سرورهاي محلي ديگر
خروجي‌هايي كه در تمام اين سال‌ها گرفته
همه را در كمتر از 30 ثانيه دسته‌بندي كرد
براي دسترسي به فايل‌ها هم
مي‌توان از ابزارهاي خوبي مانند SysTools EML Viewer استفاده نمود

سورس برنامه اين است:

package main

import (
    "io/ioutil"
    "strings"
    "time"
    "os"
    "io"
    "strconv"
)

var mFld,mPlc string
var FldCnt,MovCnt int

func main() {
    bLog("\r\n===\r\nExecuting at " + time.Now().Format("2006-01-02 15:04:05") + "\r\n")
    mFld = "~MovedEmails " + time.Now().Format("2006-01-02")
    mPlc = "AllMails " + time.Now().Format("2006-01-02")
    files, _ := ioutil.ReadDir("./")
    for _, f := range files {
          if fName := f.Name(); fName[len(fName)-4:]==".eml" {
                  bLog("Get File: "+fName+"\r\n")
                  fPath := mFld + "/" + fName
                  if _, err := os.Stat(fPath); os.IsNotExist(err) {
                      fDate,fFrom,fTo := fRead(fName)
                      mProc(fName,fDate + "-R",fTo)
                      mProc(fName,fDate + "-S",fFrom)
                      mMove(fName)
                      MovCnt++
                  }else{
                    bLog("Aborted Because Exists!\r\n")
                  }
          }
    }
    print("\nFinished: "+strconv.Itoa(MovCnt)+" Email Moved!\n")
    bLog("\r\nAll Folder Created: "+strconv.Itoa(FldCnt))
    bLog("\r\nAll Emails Moved: "+strconv.Itoa(MovCnt)+"\r\n")
    bLog("\r\nFinished at " + time.Now().Format("2006-01-02 15:04:05") + "\r\n\r\n\r\n")
}

func fRead(fName string)(fDate,fFrom,fTo string) {
  dat, err := ioutil.ReadFile(fName)
  check(err)
  fCon := string(dat)
  fFrom = gPart(fCon,"From")
  fTo = gPart(fCon,"To")
  fDate = gPart(fCon,"Date")
  bLog("From: "+fFrom+" To: "+fTo+" Date: "+fDate+"\r\n")
  if pos := strings.Index(fTo,","); pos>-1 {
    fTo = fTo[:pos]
  }
  if pos := strings.Index(fDate,","); pos>-1 {
          fDate = strings.TrimSpace(fDate[pos+1:])
    if pos = strings.Index(fDate,"("); pos>-1 {
            fDate = strings.TrimSpace(fDate[:pos])
    }
  }
  if fDate != "NotFound" {
    fDate = cDate(fDate)
  }
  return fDate, fFrom, fTo
}

func check(e error) {
    if e != nil {
        //panic(e)
        bLog("\r\n---\r\n" + e.Error() + "\r\n---\r\n")
    }
}

func gPart(fText,pName string)(s string) {
  s = "NotFound"
  fStr := "\n" + pName + ": "
  fText = "\n" + fText
  pos := strings.Index(fText, fStr)
  if pos<0 {
    pos = strings.Index(fText, strings.ToLower(fStr))
  }
  if pos>-1 {
    npos := strings.Index(fText[pos+1:],"\n")
    s = fText[pos+len(fStr):pos+npos]
    if pos=strings.Index(s,"<"); pos>-1 && strings.Index(s[pos:],">")>0 {
      s = s[pos+1:pos+strings.Index(s[pos:],">")]
    }
  }
  return strings.TrimSpace(s)
}

func cDate (t string) string {
  var tForm string
  bLog("Date Convert From: " +t)
  if t[len(t)-1:]!="0" {
          tForm = "2 Jan 2006 15:04:05 MST"
  }else{
    tForm = "2 Jan 2006 15:04:05 -0700"
    if len(t)>26 {
            t=t[:26]
    }
    if len(t)==24  {
      t=t+"00"
    }
  }
  bLog(" By Fromat: " +tForm)
  dTime, err := time.Parse(tForm, t)
  check(err)
  rTime := strings.Replace(dTime.Format("2006-01-02-15:04:05"),":","",-1)
  bLog(" To: " +rTime+ "\r\n")
  return rTime
}

func mProc(AslName, FileDate, FolName string) {
  if len(FolName)>0 {
    if strings.Index(FolName,"undisclosed")>-1 {
      return
    }
    chs := "=+\\/!&":;,\"?<"
    for i:=0;i<len(chs);i++ {
            FolName=strings.Replace(FolName,chs[i:i+1],"",-1)
    }
    FolName=strings.TrimSpace(FolName)
    if _, err := os.Stat(mPlc); os.IsNotExist(err) {
      os.Mkdir(mPlc,0777)
      bLog("Make Root Folder: "+mPlc+"\r\n")
    }
    if _, err := os.Stat(mPlc + "/" + FolName); os.IsNotExist(err) {
      os.Mkdir(mPlc + "/" + FolName,0777)
      print("Email: "+FolName+"\n")
      bLog("Make Folder: "+FolName+"\r\n")
      FldCnt++
    }
    oPath := mPlc + "/" + FolName + "/" + FileDate
    fPath := oPath + ".eml"
    for i:=1;;i++ {
            if _, err := os.Stat(fPath); err == nil {
              fPath = oPath + "-" + strconv.Itoa(i) + ".eml"
            }else{
              break
            }
    }
                in, err := os.Open(AslName)
                check(err)
                defer in.Close()
          out, err := os.Create(fPath)
          check(err)
          io.Copy(out, in)
          bLog("File Copied: "+AslName+" To: "+fPath+"\r\n")
  }
}

func mMove(AslName string) {
       if _, err := os.Stat(mFld); os.IsNotExist(err) {
    os.Mkdir(mFld,0777)
    bLog("Make Backup Folder: "+mFld+"\r\n")
        }
  fPath := mFld + "/" + AslName
  if _, err := os.Stat(fPath); os.IsNotExist(err) {
    os.Rename(AslName,fPath)
    bLog("File Moved: "+AslName+"\r\n")
  }
}

func bLog(payam string) {
  lName := "eml Organizer.log"
  f,err := os.OpenFile(lName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0660)
  check(err)
  defer f.Close()
  f.WriteString(payam)
}

مي‌توانيد از اين نشاني برداريد

يك مشكل مهم دراستفاده از زبان برنامه‌نويسي Go وجود دارد
براي ما البته
شركت توليدكننده آن
همه IPهاي داخل ايران را بسته است
فيلتر كرده يعني
و نمي‌توان به سادگي به كتابخانه‌هاي آن دسترسي داشت
از همه بدتر
وقتي از github.com سورس‌هاي آماده را برمي‌داري
خيلي‌هايشان به بسته‌هاي گوگل ارجاع داده‌اند
كه باز نمي‌شوند
و كامپايل نرم‌افزار را با مشكل روبه‌رو مي‌سازند
من براي نوشتن اين ابزار كوچك
فقط از كتابخانه‌هاي پيش‌فرض Go استفاده كردم

به عنوان اديتور
از ميان چند برنامه‌اي كه تست نمودم
Zeus را از همه راحت‌تر يافتم
و با آن نوشتم

حالا كه چه؟!
اين‌كه اكنون مي‌توانم سوابق تمام مكاتبات اينترنتي خود را مرور كنم
و اطلاعات مفيد و قابل استفاده را
باز استفاده نمايم!


مطلب بعدي: جشن تولّد مطلب قبلي: نابغه كوچك

نظرات

انيس: با عرض سلام و ادب و احترام
1. اگر ما مثلا چندهزار كتاب پي دي اف در روي رايانه داشته باشيم و هركدام از آنها را بدون كپي كردن بخواهيم در شاخه هاي مجزا داشته باشيم چه بايد بكنيم؟ مثلا همان يك فايل تفسير علامه را ، هم در قسمت تفسير داشته باشيم ، هم در قسمت طباطبايي ، هم در قسمت مذهبي و ...
2. آيا امكان شناسايي فردي كه با اسامي مختلف در سايت يا وبلاگ فعاليت دارد بدون درج ايميل خود ، براي مدير ميسر است؟
3. با اين تجارب و خلاقيتي كه داريد ، چند شغل نوآورانه و آينده دار و كم سرمايه در ايران معرفي كنيد.
بسيار ممنون . . .يكشنبه ۸ مهر ۱۳۹۷ - ۴:۳۸ عصر
پاسخ: سلام. 1. شدني‌ست، با نرم‌افزارهايي كه كارشان فهرست‌نويسي از فايل‌هاست. مثلاً Cathy كه از نشاني https://www.softpedia.com/get/System/Hard-Disk-Utils/Cathy.shtml مي‌توانيد دانلود بفرماييد. اين نرم‌افزار يك فهرست از تمام فايل‌هاي يك پوشه يا كل هارد ايجاد مي‌كند. البته نرم‌افزار بسيار ساده‌اي‌ست و رايگان. ولي نرم‌افزارهاي پولي ديگري هستند كه امكان دسته‌بندي و برچسب‌گذاري فايل‌ها را هم فراهم مي‌نمايند، مشابه آن‌چه شما فرموديد. در اين حالت، فقط يك نسخه از فايل وجود دارد، ولي نام آن در دسته‌بندي‌هاي مختلف ديده خواهد شد. 2. از روش‌هاي متعارف نمي‌شود. نياز به روش‌هاي غيرمتعارف دارد! :) 3. در كار بازار دستي ندارم و اطلاعات كافي. شغل يعني درآمد. بايد با افرادي كه درآمدزا هستند مشورت بفرماييد. من زياد به درآمد فكر نمي‌كنم، بنابراين براي درآمدزايي خيلي ايده‌اي ندارم. موفق باشيد.
Ralph Miller: Restore offline stored Outlook emails from OST file by converting it to pst file using vMail OST to PST Converterپنج‌شنبه ۲۴ خرداد ۱۳۹۷ - ۱۰:۲۷ صبح
پاسخ: Yes, But it needs 50$ yo use. My code is free! :)
OST to PST: Thanks for this information ...

دوشنبه ۱۴ اسفند ۱۳۹۶ - ۳:۵۲ عصر
پاسخ: سپاس.
بازگشتنسخه محلّي از نوشته‌هاي وبلاگ شايد سخن حق سال نشر18نوشته‌هاي وبلاگ بر اساس سال برچسب‌ها35نوشته‌هاي وبلاگ بر اساس برچسب بيشترين نظر34نوشته‌هاي وبلاگ با بيشترين تعداد نظر مجموعه‌نوشته‌ها27پست‌هاي دنباله‌دار وبلاگ
صفحه اصليبازگشت به صفحه نخست سايت نوشته‌ها986طرح‌ها، برنامه‌ها و نوشته‌ها مكان‌ها75براي چه جاهايي نوشتم زمان‌ها30همه سال‌هايي كه نوشتم جستجودستيابي به نوشته‌ها از طريق جستجو وبلاگ1366با استفاده از سامانه پارسي‌بلاگ نماها2چند فيلم كوتاه از فعاليت‌ها آواها10تعدادي فايل صوتي براي شنيدن سايت‌ها23معرفي سايت‌هاي طراحي شده نرم‌افزارها36سورس نرم‌افزارهاي خودم معرفي6معرفي طراح سايت و آثار و سوابق كاري او فونت‌هاي فارسي60تعدادي قلم فارسي كه معمولاً در نوشته‌هايم استفاده شده است بايگاني وبلاگ1354نسخه محلّي از نوشته‌هاي وبلاگ خاندان موشّحبا استفاده از سامانه شجره‌ساز خاندان حضرت زادبا استفاده از سامانه شجره‌ساز فروشگاهدسترسی به غرفه محصولات فرهنگی
با اسكن باركد صفحه را باز كنيد
تماس پيامك ايميل ذخيره
®Movashah ©2018 - I.R.IRAN