Сохраните одно вложение электронной почты в BLOB с помощью Chilkat и SQL Server - PullRequest
0 голосов
/ 08 сентября 2018

Chilkat.IMAP 9.5.0.75 - ActiveX и SQL Server

В SQL Server я перетаскиваю все новые электронные письма из почтового ящика в таблицу SQL и сохраняю UID, Subject, Body и Date. Это прекрасно работает.

Если в письме есть вложения, я пытаюсь сохранить их в отдельной таблице в виде больших двоичных объектов. Мне удалось использовать SaveAllAttachments в файловую систему, а затем импортировать их из файловой системы. Однако некоторые вложения в почтовом ящике имеют одно и то же имя файла, и я предпочел бы работать с файлами в памяти, а не сохранять их в файловой системе.

Я пытался использовать Chilkat.Email GetAttachmentData напрямую в переменную varbinary (max). Он больше 4000 байт, поэтому я попытался использовать табличную переменную. Также пытался использовать Chilkat.IMAP FetchAttachmentBytes таким же образом с теми же результатами:

Непосредственно в переменную varbinary (max):


declare @bin_file varbinary(max)
EXEC sp_OAMethod @email, 'GetAttachmentData', @bin_file out, @j

Результаты:


ChilkatLog:
  GetAttachmentData:
    DllDate: Aug 25 2018
    ChilkatVersion: 9.5.0.75
    UnlockPrefix: ***************
    Architecture: Little Endian; 64-bit
    Language: ActiveX / x64
    VerboseLogging: 0
    index: 0
    numBytes: 426484
    Success.
  --GetAttachmentData
--ChilkatLog

@ bin_file равен нулю, хотя и говорит об успехе. Я думаю, что это связано с ограничением в 4000 байт, но я не уверен.

Для табличной переменной со столбцом varbinary (max):


DECLARE @attach TABLE (attachment varbinary(max))
INSERT INTO @attach EXEC sp_OAMethod @email, 'GetAttachmentData', @j

Результаты:


ChilkatLog:
  GetHeaderField:
    ChilkatVersion: 9.5.0.75
  --GetHeaderField
--ChilkatLog

По какой-то причине в журнале отображается предыдущая команда, а не GetAttachmentData, как если бы SQL пропускал этот оператор. Я использую тот же самый подход к табличным переменным, чтобы успешно получить свойство тела письма. Результаты одинаковы, независимо от того, использую ли я Chilkat.Email.GetAttachmentData или Chilkat.IMAP.FetchAttachmentBytes.

Вот весь сценарий:

   

CREATE TABLE #email_uid (uid VARCHAR(1024))   


DECLARE @hr int
DECLARE @iTmp0 int
DECLARE @sTmp0 nvarchar(4000)
DECLARE @imap int

EXEC @hr = sp_OACreate 'Chilkat_9_5_0.Imap', @imap OUT
IF @hr <> 0
BEGIN
    PRINT 'Failed to create ActiveX component'
    RETURN
END

--  Anything unlocks the component and begins a fully-functional 30-day trial.
DECLARE @success int
EXEC sp_OAMethod @imap, 'UnlockComponent', @success OUT, 'hidden'
IF @success <> 1
  BEGIN
    EXEC sp_OAGetProperty @imap, 'LastErrorText', @sTmp0 OUT
    PRINT @sTmp0
    EXEC @hr = sp_OADestroy @imap
    RETURN
  END

--  Connect to an IMAP server.
--  Use TLS
EXEC sp_OASetProperty @imap, 'Ssl', 1
EXEC sp_OASetProperty @imap, 'Port', 993
EXEC sp_OAMethod @imap, 'Connect', @success OUT, 'hidden'
IF @success <> 1
  BEGIN
    EXEC sp_OAGetProperty @imap, 'LastErrorText', @sTmp0 OUT
    PRINT @sTmp0
    EXEC @hr = sp_OADestroy @imap
    RETURN
  END

--  Login
EXEC sp_OAMethod @imap, 'Login', @success OUT, 'hidden account name', 'hidden password'
IF @success <> 1
  BEGIN
    EXEC sp_OAGetProperty @imap, 'LastErrorText', @sTmp0 OUT
    PRINT @sTmp0
    EXEC @hr = sp_OADestroy @imap
    RETURN
  END

--  Select an IMAP mailbox
EXEC sp_OAMethod @imap, 'SelectMailbox', @success OUT, 'Inbox'
IF @success <> 1
  BEGIN
    EXEC sp_OAGetProperty @imap, 'LastErrorText', @sTmp0 OUT
    PRINT @sTmp0
    EXEC @hr = sp_OADestroy @imap
    RETURN
  END

DECLARE @messageSet int

--  fetch UIDs not sequence numbers.
DECLARE @fetchUids int
SELECT @fetchUids = 1

--  Return all messages.
DECLARE @allMsgs nvarchar(4000)
SELECT @allMsgs = 'ALL'

EXEC sp_OAMethod @imap, 'Search', @messageSet OUT, @allMsgs, @fetchUids
IF @messageSet Is NULL 
  BEGIN
    EXEC sp_OAGetProperty @imap, 'LastErrorText', @sTmp0 OUT
    PRINT @sTmp0
    EXEC @hr = sp_OADestroy @imap
    RETURN
  END

--  Fetch the email headers into a bundle object:
DECLARE @bundle int

EXEC sp_OAMethod @imap, 'FetchHeaders', @bundle OUT, @messageSet
IF @bundle Is NULL 
  BEGIN
    EXEC @hr = sp_OADestroy @messageSet

    EXEC sp_OAGetProperty @imap, 'LastErrorText', @sTmp0 OUT
    PRINT @sTmp0
    EXEC @hr = sp_OADestroy @imap
    RETURN
  end

-- get all UID's from the inbox; loop through them and download the if we haven't downloaded that UID before
DECLARE @i int

EXEC sp_OAGetProperty @bundle, 'MessageCount', @iTmp0 OUT
SELECT @i = 0
WHILE @i <= @iTmp0 - 1
  BEGIN
    DECLARE @email int

    EXEC sp_OAMethod @bundle, 'GetEmail', @email OUT, @i
    EXEC sp_OAMethod @email, 'GetHeaderField', @sTmp0 OUT, 'ckx-imap-uid'

    insert into #email_uid
    select @sTmp0

    EXEC @hr = sp_OADestroy @email

    SELECT @i = @i + 1
  end

-- delete UIDs we have already downloaded
  delete a
  from #email_uid a
  inner join email b on b.uid = a.uid

  declare @bUid int
      select @bUid = 1

  declare @s varchar(1024)

  select @s = min(uid) from #email_uid

  while exists (select 1 from #email_uid)
  begin

    --  Download the email by UID number.
    EXEC sp_OAMethod @imap, 'FetchSingle', @email OUT, @s, @bUid

    -- get number of attachments in the email
    DECLARE @numAttach int
    EXEC sp_OAMethod @imap, 'GetMailNumAttach', @numAttach OUT, @email

    declare @subject varchar(1024)
          , @date varchar(1024)
          , @from varchar(1024)
          , @body varchar(max)

    -- Fetch a longer property string into a temp table:
    DECLARE @tmp TABLE (emailBody ntext)
    INSERT INTO @tmp EXEC sp_OAGetProperty @email, 'Body'

    select @body = emailBody from @tmp

    EXEC sp_OAGetProperty @email, 'Subject', @subject out
    EXEC sp_OAGetProperty @email, 'From', @from out
    EXEC sp_OAMethod @email, 'GetHeaderField', @date OUT, 'Date'

    insert email ([UID],[Subject],[Date],[from],[Body])
    select @s, @subject, @date, @from, @body

    set @subject = null
    set @from    = null
    set @date    = null
    set @body    = null

    DECLARE @j int

    -- Loop through the attachments and insert them as BLOBS into attachment table
        SELECT @j = 0
        WHILE @j <= @numAttach - 1
          BEGIN
            DECLARE @filename nvarchar(4000)
            EXEC sp_OAMethod @imap, 'GetMailAttachFilename', @filename OUT, @email, @j
            PRINT @filename

            DECLARE @attach TABLE (attachment varbinary(max))
            INSERT INTO @attach EXEC sp_OAMethod @email, 'GetAttachmentData', @j

            IF not exists (select 1 from @attach) 
            BEGIN
              EXEC sp_OAGetProperty @email, 'LastErrorText', @sTmp0 OUT
              PRINT @sTmp0
              EXEC @hr = sp_OADestroy @email
              EXEC @hr = sp_OADestroy @imap
              RETURN
            end

            --declare @bin_file varbinary(max)
            --EXEC sp_OAMethod @email, 'GetAttachmentData', @bin_file out, @j
            --if @bin_file is null
            --BEGIN
              --EXEC sp_OAGetProperty @email, 'LastErrorText', @sTmp0 OUT
              --PRINT @sTmp0
              --EXEC @hr = sp_OADestroy @email
              --EXEC @hr = sp_OADestroy @imap
              --RETURN
           --END

            insert into [dbo].[email_attachment] (UID,Filename,Attachment)
            select @s, @filename, attachment
            from @attach

            delete @attach

            select @j = @j + 1
          END

 EXEC @hr = sp_OADestroy @email

 delete from #email_uid where uid = @s

 select @s = min(uid) from #email_uid

 end

--  Disconnect from the IMAP server.
EXEC sp_OAMethod @imap, 'Disconnect', @success OUT

EXEC @hr = sp_OADestroy @messageSet
EXEC @hr = sp_OADestroy @bundle
EXEC @hr = sp_OADestroy @imap

Спасибо, Дарин

1 Ответ

0 голосов
/ 10 сентября 2018

Имя метода должно быть GetAttachmentData (не GetAttachmentBytes). Смотри https://www.chilkatsoft.com/refdoc/xChilkatEmailRef.html#method72

Я не уверен, почему SQL не выдавал / не возвращал ошибку, когда вы использовали имя «GetAttachmentBytes». Кажется, он только что пропустил это утверждение.

...