embedding image in body of email from vb.net - html

I have rigorously searched for a soln on this but cannot get this to work. I am trying to send an email from within a vb.net application where an image is embedded in the body of the email. I get it to work as an attachment but in outlook and other email clients, the image does not show. The image is stored locally and I wonder if that has anything to do with it. I tried adding the image within a string first and that did not work;
emailString.AppendLine()
emailString.AppendLine()
emailString.AppendLine("<br />")
emailString.AppendLine("<br />")
emailString.AppendLine("<img src =""cid:C:\Users\Public\Pictures\Sample Pictures\br1.gif"" alt='STUPID IMAGE'>")
then tried a different way with linkedresource
Sub SendEmail(ByVal errorMessage As String)
Dim mail As New MailMessage()
mail.From = New MailAddress("med#person.com", "**DAILY STATS**")
mail.Subject = "STATS ALERT"
mail.To.Add("med#person.com")
mail.IsBodyHtml = True
'mail.Body = "TEST EMAIL" 'errorMessage
'mail.BodyEncoding = Encoding.UTF8
smptpServer.Timeout = 30000
smptpServer.Credentials = New NetworkCredential("me", "person")
Dim imageBody As String = " <img src =""cid:C:\Users\Public\Pictures\Sample Pictures\br1.gif"">"
Dim htmlView As System.Net.Mail.AlternateView = System.Net.Mail.AlternateView.CreateAlternateViewFromString(errorMessage, Nothing, "text/html")
Dim plainTextView As System.Net.Mail.AlternateView = System.Net.Mail.AlternateView.CreateAlternateViewFromString(errorMessage, Nothing, "text/plain")
Dim imageResource As New System.Net.Mail.LinkedResource("C:\Users\Public\Pictures\Sample Pictures\br1.gif", MediaTypeNames.Image.Gif)
Dim attachment As System.Net.Mail.Attachment
attachment = New System.Net.Mail.Attachment("C:\Users\Public\Pictures\Sample Pictures\br1.gif")
mail.Attachments.Add(attachment)
'imageResource.ContentId = "HDIImage"
htmlView.LinkedResources.Add(imageResource)
htmlView.TransferEncoding = Net.Mime.TransferEncoding.Base64
htmlView.ContentType = New System.Net.Mime.ContentType("text/html")
'mail.AlternateViews.Add(plainTextView)
mail.AlternateViews.Add(htmlView)
Try
smptpServer.Send(mail)
Catch ex As Exception
If ex.Message.Contains("Timeout") Then
Exit Sub
End If
End Try
I even changed the image type from png to gif. The normal manually created html tables work when appending it to the string but this above way does not work.
Only this appears:

It seems to me that if your image goes attached to the email, your src attribute should be "cid:imagename.png", without a disk path. Take a look at this: embedding image in html email

For those that are looking for a "final version" of a VB.NET code that is working and/or a way to add more than one image, this is what I finally ended up. Basically, this embed 2 images in a signature at the bottom of the message :
Image1 = New Net.Mail.LinkedResource(Directory.GetCurrentDirectory + "\mailsrvr\image001.jpg", "image/jpeg")
Image1.ContentId = Guid.NewGuid().ToString()
Image2 = New Net.Mail.LinkedResource(Directory.GetCurrentDirectory + "\mailsrvr\image002.jpg", "image/jpeg")
Image2.ContentId = Guid.NewGuid().ToString()
Signature = Replace(Replace(Signature, "image001.jpg", Image1.ContentId), "image002.jpg", Image2.ContentId)
myMessage.Body = myMessage.Body & Signature
Dim View = Net.Mail.AlternateView.CreateAlternateViewFromString(myMessage(msgInd).Body, Nothing, "text/html")
View.LinkedResources.Add(Image1)
View.LinkedResources.Add(Image2)
myMessage.AlternateViews.Add(View)

Related

LibreOffice Basic Macro command converting Calc cellRange to RTF/HTML

My goal is to fill a LibreOffice calc sheet, and silently send a cell range by email when the user clicks the send-off button (and once more to confirm).
So there is three part to this.
A push button with a request to confirm. (Easy and done.)
Select Cell Range and turn it into rich text format (Haven't yet found)
Send rich text email from within the sheet. (Will tackle the "silent" part later)
I tried copying the range to the clipboard with unoService but it seemed over-complicated and full of errors.
Here's what I have:
''''Send by e-mail enriched text
Sub Main
Dim Doc, Sheet, Range, Rtf, Exec as Object
End Sub
'Confirm it
Sub SendTableApproval
If MsgBox ("Ready to email?", MB_YESNO + MB_DEFBUTTON2) = IDYES Then
CopyTable()
End If
End Sub
'Copy it
Sub CopyTable
Doc = ThisComponent
View = Doc.CurrentController
Frame = View.Frame
Sheet = Doc.Sheets.getByIndex(0)
Range = Sheet.getCellrangeByName("a1:f45")
Exec = createUnoService("com.sun.star.frame.DispatchHelper")
View.Select(Range)
Cells = View.getTransferable()
Exec.executeDispatch(Frame, ".uno:Deselect", "", 0, array())
'SimpleMailTo(Cells)
End Sub
'Mail it
Sub SimpleMailTo(body)
Dim launcher as object
Dim eAddress, eSubject, eBody, aHTMLanchor as string
launcher = CreateUnoService("com.sun.star.system.SystemShellExecute")
eAddress = "tu#domo.eg"
eSubject = "Cotidie agenda futuendane"
eBody = body
aHTMLanchor = "mailto:" & eAddress & "?subject=" & eSubject & "&&body=" & eBody
launcher.execute(aHTMLanchor, "", 0)
End Sub
I still do not know after three days of research over methods, properties, uno.
My question is, simply put, How can I convert a transferable content to HTML/RTF?
Simply copying and pasting into an email produces the result you are asking for. The code on the LibreOffice side should look like this.
dispatcher.executeDispatch(document, ".uno:Copy", "", 0, Array())
It sounds like you already tried this, but something didn't work. Perhaps you could elaborate on what went wrong.
Another approach would be to write the spreadsheet to a temporary HTML or XHTML file. Then parse the temporary file to grab the part needed for the email.
AFAIK there is no such command to turn a cell range into rich text format with UNO. To do it that way, you would need to loop through each text range of each cell, read its formatting properties and then generate the HTML yourself.
EDIT:
Good idea about XTransferable. The following Java code adapted from the DevGuide gets an HTML string and then prints it. I believe this would be a good solution for your needs.
public void displayHTMLFromClipboard()
{
try
{
Object oClipboard = xMCF.createInstanceWithContext(
"com.sun.star.datatransfer.clipboard.SystemClipboard", xContext);
XClipboard xClipboard = (XClipboard)
UnoRuntime.queryInterface(XClipboard.class, oClipboard);
XTransferable xTransferable = xClipboard.getContents();
DataFlavor[] aDflvArr = xTransferable.getTransferDataFlavors();
System.out.println("Available clipboard formats:");
DataFlavor aChosenFlv = null;
for (int i=0;i<aDflvArr.length;i++)
{
System.out.println(
"MimeType: " + aDflvArr[i].MimeType +
" HumanPresentableName: " + aDflvArr[i].HumanPresentableName );
if (aDflvArr[i].MimeType.equals("text/html"))
{
aChosenFlv = aDflvArr[i];
}
}
System.out.println("");
try
{
if (aChosenFlv != null)
{
System.out.println("HTML text on the clipboard...");
Object aData = xTransferable.getTransferData(aChosenFlv);
String s = new String((byte[])aData, Charset.forName("ISO-8859-1"));
System.out.println(s);
}
}
catch (UnsupportedFlavorException exc)
{
exc.printStackTrace();
}
}
catch(com.sun.star.uno.Exception exc)
{
exc.printStackTrace();
}
}
If you plan to use Basic, it might be a good idea to do some research into the proper way to convert bytes. The code I have below seems to work but is probably unreliable and unsafe, and will not work for many languages. A few of my initial attempts crashed before this finally worked.
Sub DisplayClipboardData
oClipboard = createUnoService("com.sun.star.datatransfer.clipboard.SystemClipboard")
xTransferable = oClipboard.getContents()
aDflvArr = xTransferable.getTransferDataFlavors()
For i = LBound(aDflvArr) To UBound(aDflvArr)
If aDflvArr(i).MimeType = "text/html" Then
Dim aData() As Byte
aData = xTransferable.getTransferData(aDflvArr(i))
Dim s As String
For j = LBound(aData) to UBound(aData)
s = s & Chr(aData(j)) 'XXX: Probably a bad way to do this!
Next j
Print(s)
End If
Next
End Sub
One more suggestion: Python might be a better language choice here. In many ways, using Python with LibreOffice is easier than Java. And unlike Basic, Python is powerful enough to comfortably handle byte strings.

VB.net Autocomplete Textbox filter using mysql database as custom source

I'm Having a problem regarding to the autocomplete textbox. First I already made the autocomplete textbox work with mysql database as custom source but the default textfilter of autocomplete is "start with" not "contains". I want to change the textfilter to "contains", so that when I search any part of the string, the whole name which contains the searched word will appear in the autocomplete suggestions.
Can anyone help me fix my code?
This is the code i've done so far:
txtSearch.AutoCompleteMode = AutoCompleteMode.SuggestAppend
txtSearch.AutoCompleteSource = AutoCompleteSource.CustomSource
Dim DataCollection As New AutoCompleteStringCollection()
Dim query As String
sqlcon = New MySqlConnection
sqlcon.ConnectionString =
"server=localhost;userid=root;password=root;database=svfmemberlistdb"
Try
sqlcon.Open()
query = " SELECT Name FROM svfmemberlistdb.svfmemberlist "
sqlcmd = New MySqlCommand(query, sqlcon)
sqladr.SelectCommand = sqlcmd
sqladr.Fill(ds)
sqladr.Dispose()
sqlcon.Close()
For Each row As DataRow In ds.Tables(0).Rows
If row.ToString.Contains(txtSearch.Text) Then
DataCollection.Add(row(0).ToString())
End If
Next
Catch ex As Exception
End Try
txtSearch.AutoCompleteCustomSource = DataCollection
I quote here Mitja Bonca's answer on MSDN.
In this case, autocompletemode will just not do. Its code is not meant
for something like it.
You will have to do your own code, to do the filtering on each letter
press.
So I would suggest not to use autocompletemode, and get all the data
(names) into dataTable. When user presses some button ("1" for
example), you start with your filtering, by creating new Datatable
(leave the main one untached - so you can return back to all data when
clearing comboBox by backspace), with Copy() method - to create a full
copy of original one, and use Select method to do the filteing.
This should look something like by using % simbol on both sides of a
string - to filter inbetween - this is what you want!
DataTable AllNames = new DataTable();
//fill it up and leave it untouched!
//to filter comboBox with names that contains pressed characters do in
private void comboBox1_KeyPress(object sender, KeyPressEventArgs e)
{
string name = string.Format("{0}{1}", comboBox1.Text, e.KeyChar.ToString()); //join previous text and new pressed char
DataRow[] rows = table.Select(string.Format("FieldName LIKE '%{0}%'", name));
DataTable filteredTable = AllNames.Clone();
foreach(DataRow r in rows)
filteredTable.ImportRow(r);
comboBox1.DataSource = null;
comboBox1.DataSource = filteredTable.DefaultView;
comboBox1.DisplayMember = "FieldName";
}
Reference
EDIT: This is of course a c# answer not VB.NET but it might be helpful to get the concept.

Reading HTML page using Libreoffice Basic

I'm new to LibreOffice Basic. I'm trying to write a macro in LibreOffice Calc that will read the name of a noble House of Westeros from a cell (e.g. Stark), and output the Words of that House by looking it up on the relevant page on A Wiki of Ice and Fire. It should work like this:
Here is the pseudocode:
Read HouseName from column A
Open HtmlFile at "http://www.awoiaf.westeros.org/index.php/House_" & HouseName
Iterate through HtmlFile to find line which begins "<table class="infobox infobox-body"" // Finds the info box for the page.
Read Each Row in the table until Row begins Words
Read the contents of the next <td> tag, and return this as a string.
My problem is with the second line, I don't know how to read a HTML file. How should I do this in LibreOffice Basic?
There are two mainly issues with this.
1. Performance
Your UDF will need get the HTTP resource in every cell, in which it is stored.
2. HTML
Unfortunately there is no HTML parser in OpenOffice or LibreOffice. There is only a XML parser. Thats why we cannot parse HTML directly with the UDF.
This will work, but slow and not very universal:
Public Function FETCHHOUSE(sHouse as String) as String
sURL = "http://awoiaf.westeros.org/index.php/House_" & sHouse
oSimpleFileAccess = createUNOService ("com.sun.star.ucb.SimpleFileAccess")
oInpDataStream = createUNOService ("com.sun.star.io.TextInputStream")
on error goto falseHouseName
oInpDataStream.setInputStream(oSimpleFileAccess.openFileRead(sUrl))
on error goto 0
dim delimiters() as long
sContent = oInpDataStream.readString(delimiters(), false)
lStartPos = instr(1, sContent, "<table class=" & chr(34) & "infobox infobox-body" )
if lStartPos = 0 then
FETCHHOUSE = "no infobox on page"
exit function
end if
lEndPos = instr(lStartPos, sContent, "</table>")
sTable = mid(sContent, lStartPos, lEndPos-lStartPos + 8)
lStartPos = instr(1, sTable, "Words" )
if lStartPos = 0 then
FETCHHOUSE = "no Words on page"
exit function
end if
lEndPos = instr(lStartPos, sTable, "</tr>")
sRow = mid(sTable, lStartPos, lEndPos-lStartPos + 5)
oTextSearch = CreateUnoService("com.sun.star.util.TextSearch")
oOptions = CreateUnoStruct("com.sun.star.util.SearchOptions")
oOptions.algorithmType = com.sun.star.util.SearchAlgorithms.REGEXP
oOptions.searchString = "<td[^<]*>"
oTextSearch.setOptions(oOptions)
oFound = oTextSearch.searchForward(sRow, 0, Len(sRow))
If oFound.subRegExpressions = 0 then
FETCHHOUSE = "Words header but no Words content on page"
exit function
end if
lStartPos = oFound.endOffset(0) + 1
lEndPos = instr(lStartPos, sRow, "</td>")
sWords = mid(sRow, lStartPos, lEndPos-lStartPos)
FETCHHOUSE = sWords
exit function
falseHouseName:
FETCHHOUSE = "House name does not exist"
End Function
The better way would be, if you could get the needed informations from a Web API that would offered from the Wiki. You know the people behind the Wiki? If so, then you could place this there as a suggestion.
Greetings
Axel

C# get the selected text in the body of the email for MS Outlook 2007

I am using C# and outlook-addin.
I want to be able to have the user select a part of the mail message/body and I want to be able to copy the selected items, and it store it to an sql server database.
Outlook.Application myApplication = Globals.ThisAddIn.Application;
Outlook.Explorer myActiveExplorer =
(Outlook.Explorer)myApplication.ActiveExplorer();
Outlook.Selection selection = myActiveExplorer.Selection;
if (selection.Count == 1 && selection[1] is Outlook.MailItem)
{
Outlook.MailItem mail = (Outlook.MailItem)selection[1];
mail.Copy(); // currently opened mail
Outlook.MailItem mailItem = (Outlook.MailItem)
myApplication.CreateItem(
Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
mailItem.Subject = mail.Subject;
mailItem.To = mail.To;
mailItem.Body = ????? // copy only selected text/images of user
mailItem.Importance = Outlook.OlImportance.olImportanceLow;
mailItem.Display(true);
}
On the mailITem.Body, I just want to paste the selected text/images of the user from the selected mail (the currently opened email).
I cant find the paste method, How can I implement it?
Outlook cannot get the selected text in the mail body, so convert the outlook to word editor, so you can follow these 3 steps:
1. get the mail total body
2. use the word editor based on the **microsoft.office.Interop.word** dll
3. select the text and to store the any string
first add the dll reference
object oItem;
Outlook.Application oApp=new Outlook.Application();
Outlook.Explorer oExp=oApp.ActiveExplorer();
Outlook.Selection oSel= oExp.Selection;
for (i = 1; i <= oSel.Count; i++)
{
oItem = oSel[i];
Outlook.MailItem oMail = (Outlook.MailItem)oItem;
Outlook.Inspector inspector = oMail.GetInspector;
// Obtain the Word.Document object from the Inspector object
Microsoft.Office.Interop.Word.Document document =
(Microsoft.Office.Interop.Word.Document)inspector.WordEditor;
mailItem.Body = document.Application.Selection.Text;
}

SSRS 2008 Export Report to Image Only Exports First Page

Ok, so i am working on exporting my SSRS 2008 Reports to an image. What I would like to do is Export each individual page as an image. From my code, I can only get it to export the first page of the report. Any help would greatly be appreciated.
Dim warnings As Microsoft.Reporting.WebForms.Warning()
Dim streamids As String()
Dim mimeType, encoding, extension As String
Dim deviceInfo As XElement = _
<DeviceInfo>
<OutputFormat>JPEG</OutputFormat>
</DeviceInfo>
Report.ServerReport.SetParameters(Parameters)
Dim bytes As Byte() = Report.ServerReport.Render("Image", deviceInfo.ToString(), mimeType, encoding, extension, streamids, warnings)
Dim FileStream As New MemoryStream(bytes)
Dim ReportImage As New System.Drawing.Bitmap(FileStream)
ReportImage.Save(Server.MapPath("/Testing.jpg"), System.Drawing.Imaging.ImageFormat.Jpeg)
in one of my projects I use the following code to obtain one stream per page. Unfortunately I don't use VB.NET, but you should be able to translate this from C# to VB. Note: This works on SSRS2005 - I'm not sure it also works for SSRS2008! Also, I'm using the code to directly print the report without having to use the report viewer, so I'm creating an EMF device info - you might have to change this.
This base code was found somewhere on the Web after Googling for hours - I'd like to credit the author, but I didn't bookmark the link - sorry.
CultureInfo us = new CultureInfo("en-US");
string deviceInfo = String.Format(
"<DeviceInfo>" +
" <OutputFormat>EMF</OutputFormat>" +
" <PageWidth>{0}cm</PageWidth>" +
" <PageHeight>{1}cm</PageHeight>" +
" <MarginTop>{2}cm</MarginTop>" +
" <MarginLeft>{3}cm</MarginLeft>" +
" <MarginRight>{4}cm</MarginRight>" +
" <MarginBottom>{5}cm</MarginBottom>" +
"</DeviceInfo>",
Math.Round(m_pageSize.Width, 2).ToString(us),
Math.Round(m_pageSize.Height, 2).ToString(us),
Math.Round(m_marginTop, 2).ToString(us),
Math.Round(m_marginLeft, 2).ToString(us),
Math.Round(m_marginRight, 2).ToString(us),
Math.Round(m_marginBottom, 2).ToString(us));
m_reportStreams = new List<Stream>();
try
{
// Tell SSRS to store one stream per page on server
NameValueCollection urlAccessParameters = new NameValueCollection();
urlAccessParameters.Add("rs:PersistStreams", "True");
// Render first page
Stream s = viewer.ServerReport.Render("IMAGE", deviceInfo, urlAccessParameters, out mime, out extension);
m_reportStreams.Add(s);
// Loop to get other streams
urlAccessParameters.Remove("rs:PersistStreams");
urlAccessParameters.Add("rs:GetNextStream", "True");
do
{
s = viewer.ServerReport.Render("IMAGE", deviceInfo, urlAccessParameters, out mime, out extension);
if (s.Length != 0) m_reportStreams.Add(s);
}
while (s.Length > 0);
// Now there's one stream per page - do stuff with it
}
finally
{
foreach (Stream s in m_reportStreams)
{
s.Close();
s.Dispose();
}
m_reportStreams = null;
}
EDIT
Forgot to mention that viewer is a programmatically created instance of the ReportViewer control initialized to render the report that you're trying to print/save.