VB.NET | Blog | Limilabs https://www.limilabs.com/blog Using Limilabs .net components Thu, 03 Jul 2025 13:35:56 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.5 IMAP component for .NET https://www.limilabs.com/blog/imap-component-for-net Wed, 29 Nov 2023 11:51:36 +0000 http://www.limilabs.com/blog/?p=219 Mail.dll email component includes an excellent IMAP email component. Unleash the full potential of email management with Mail.dll’s outstanding IMAP email component. It offers .NET developers an unparalleled tool for handling IMAP email protocol. From retrieving messages to managing folders and attachments, the IMAP component in Mail.dll simplifies complex tasks into user-friendly functions. Mail.dll is […]

The post IMAP component for .NET first appeared on Blog | Limilabs.

]]>
Mail.dll email component includes an excellent IMAP email component. Unleash the full potential of email management with Mail.dll’s outstanding IMAP email component.

It offers .NET developers an unparalleled tool for handling IMAP email protocol. From retrieving messages to managing folders and attachments, the IMAP component in Mail.dll simplifies complex tasks into user-friendly functions.

Mail.dll is available for all regular .NET framework versions as well as for most recent .net 6, 7, 8 and .net 9 and higher.

IMAP, short for Internet Message Access Protocol, is one of the two most prevalent Internet standard protocols for e-mail retrieval, the other being Post Office Protocol – POP3 (also available in Mail.dll).

IMAP has many advantages over POP3, most important are using folders to group emails, saving seen/unseen state of the messages and search capability.

This article is going to show how easy is to connect to use IMAP client from .NET, download and parse unseen messages.

Installation

The easiest way to install Mail.dll is to download it from nuget via Package Manager:

PM> Install-Package Mail.dll

Alternatively you can download Mail.dll directly from our website.

Connect to IMAP

First you need connect to IMAP server. You should use Imap class for that. Using block ensures that IMAP connection is properly closed and disposed when you’re done.

using(Imap imap = new Imap())

In most cases you should be using TLS secured connection – ConnectSSL method will choose a correct port and perform SSL/TLS negotiation, then you perform IMAP authentictation:

	imap.ConnectSSL("imap.server.com");
	imap.UseBestLogin("user", "password");

Mail.dll supports OAuth 2.0 for authentication, you can find OAuth2 samples for Office365 and Gmail on the Mail.dll samples page.

For Gmail you may want to use Gmail’s App Passwords.

Search for unseen emails

As IMAP groups messages into folder you need to select a well know INBOX folder. All new, received emails are first placed in the INBOX folder first:

imap.SelectInbox();

Then you perform a search that find all unseen messages

List<long> uids = imap.Search(Flag.Unseen);

Download and parse emails

Finally you download emails one-by-one and parse them. You should use MailBuider class to parse emails:

var eml = imap.GetMessageByUID(uid);
IMail email = new MailBuilder().CreateFromEml(eml);

Entire code to download emails in .net

Entire code to download emails using IMAP is less than 20 lines:

using(Imap imap = new Imap())
{
	imap.ConnectSSL("imap.server.com");	// or Connect for no TLS
	imap.UseBestLogin("user", "password");

	imap.SelectInbox();
	List<long> uids = imap.Search(Flag.Unseen);

	foreach (long uid in uids)
	{
		var eml = imap.GetMessageByUID(uid);
		IMail email = new MailBuilder().CreateFromEml(eml);

		string subject = mail.Subject;
	}
	imap.Close();
}

and for those who like VB.NET more:

Using imap As New Imap()
	imap.ConnectSSL("imap.server.com")
	imap.UseBestLogin("user", "password")

	imap.SelectInbox()
	Dim uids As List(Of Long) = imap.Search(Flag.Unseen)

	For Each uid As Long In uids
		Dim mail As IMail = New MailBuilder()_
			.CreateFromEml(imap.GetMessageByUID(uid))

		Console.WriteLine(mail.Subject)
	Next
	imap.Close()
End Using

It can’t get much simpler than that!

Summary

You can use Mail.dll .NET IMAP component to:

It works perfectly with Exchange, Office365, Gmail and all other IMAP servers.

Just give Mail.dll a try and download it at: Mail.dll .NET IMAP component


Get Mail.dll

The post IMAP component for .NET first appeared on Blog | Limilabs.

]]>
How to search IMAP in .NET https://www.limilabs.com/blog/how-to-search-imap-in-net https://www.limilabs.com/blog/how-to-search-imap-in-net#comments Mon, 31 Jul 2023 13:49:47 +0000 http://www.limilabs.com/blog/?p=181 One of many advantages IMAP protocol has over POP3 protocol is the ability to search. There are several ways of performing search using Mail.dll .NET IMAP library: IMAP search is done entirely on the server side, which means that it’s fast and doesn’t require Mail.dll client to download much data over the network. Installation The […]

The post How to search IMAP in .NET first appeared on Blog | Limilabs.

]]>
One of many advantages IMAP protocol has over POP3 protocol is the ability to search.

There are several ways of performing search using Mail.dll .NET IMAP library:

  • Search(Flag) – for common flag searches (seen, unseen, …).
  • SimpleImapQuery – easy one object query, where all conditions are joined with an AND operator.
  • Expression syntax – most advanced, allows using AND and OR operators and sorting.

IMAP search is done entirely on the server side, which means that it’s fast and doesn’t require Mail.dll client to download much data over the network.

Installation

The easiest way to install Mail.dll IMAP client for .NET is to download it from nuget via Package Manager:

PM> Install-Package Mail.dll

Alternatively you can download Mail.dll directly from our website.

Connect to IMAP

Let’s start with the basics: we’ll connect to the IMAP server in .NET app and authenticate:

// C# code:

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap.example.com");
    imap.UseBestLogin("user", "password");
    imap.SelectInbox();

    // Search code goes here

    imap.Close();
}
' VB.NET code:

Using imap As New Imap()
    imap.ConnectSSL("imap.example.com")
    imap.UseBestLogin("user", "password")
    imap.SelectInbox()

    ' Search code here

    imap.Close()
End Using

When using Gmail you can use application passwords, with Office 365 you’ll need to use OAuth 2.0 to authenticate.

Mail.dll fully supports OAuth 2.0 for authentication, you can find OAuth2 samples for Office365 and Gmail on the Mail.dll samples page.

Search(Flag)

Now, let’s look at the search code. The first and the simplest way to search is by using Imap.Search(Flag) method. This sample below finds all unseen email messages (those that have \UNSEEN flag).

// C#

List<long> uidList = imap.Search(Flag.Unseen);

// now download each message and get the subject
foreach (long uid in uidList)
{
    IMail message = new MailBuilder()
        .CreateFromEml(imap.GetMessageByUID(uid));

    string subject = message.Subject;
}
' VB.NET

Dim uidList As List(Of Long) = imap.Search(Flag.Unseen)

' now download each message and get the subject
For Each uid As Long In uidList
	Dim message As IMail = New MailBuilder()_
		.CreateFromEml(imap.GetMessageByUID(uid))

	Dim subject As String = message.Subject
Next

SimpleImapQuery

Second approach is to use an IMAP query object. The sample below searches for all unseen emails with a certain subject. All non-null SimpleImapQuery properties are combined using and operator.

// C#

SimpleImapQuery query = new SimpleImapQuery();
query.Subject = "subject to search";
query.Unseen = true;

List<long> uids = imap.Search(query);
' VB.NET

Dim query As New SimpleImapQuery()
query.Subject = "subject to search"
query.Unseen = True

Dim uids As List(Of Long) = imap.Search(query)

Expression syntax

Finally, the most advanced search option using Expression class. You can use AND, OR and NOT operators in your IMAP search.

Note that Mail.dll fully encapsulates IMAP search syntax, with easy to use and very readable .NET classes:

// C#

List<long> uids = imap.Search().Where(
    Expression.And(
        Expression.Not(Expression.Subject("subject not to search")),
        Expression.HasFlag(Flag.Unseen)));
' VB.NET

Dim uids As List(Of Long) = imap.Search().Where(_
    Expression.[And](_
        Expression.[Not](Expression.Subject("subject not to search")),_
        Expression.HasFlag(Flag.Unseen)))

Expression syntax with sorting

Expression search syntax also allows sorting (defined in RFC 5256).

This feature is not available for every IMAP server: you need to check if your IMAP server supports ImapExtension.Sort extension first.

// C#

List<long> uids = imap.Search()
    .Where(Expression.And(
            Expression.Not(Expression.Subject("subject not to search")),
            Expression.HasFlag(Flag.Unseen)))
    .Sort(SortBy.Multiple(
            SortBy.Date(),
            SortBy.Subject()));
' VB.NET

Dim uids As List(Of Long) = imap.Search() _
    .Where(Expression.[And]( _
        Expression.[Not](Expression.Subject("subject not to search")), _
        Expression.HasFlag(Flag.Unseen))) _
    .Sort(SortBy.Multiple( _
        SortBy.[Date](), _
        SortBy.Subject()))
)

Notice the neat trick in Mail.dll .NET client, that allows casting FluentSearch class, received from imap.Search() method, to List<longs>:

public static implicit operator List<long>(FluentSearch search)
{
        return search.GetList();
}

We tend to use it very often for builder objects used in our unit tests.

Suggested reading

If you like it just give it a try and download it at: Mail.dll .NET IMAP component


Get Mail.dll

The post How to search IMAP in .NET first appeared on Blog | Limilabs.

]]>
https://www.limilabs.com/blog/how-to-search-imap-in-net/feed 36
Save all attachments to disk using IMAP https://www.limilabs.com/blog/save-all-attachments-to-disk-using-imap https://www.limilabs.com/blog/save-all-attachments-to-disk-using-imap#comments Fri, 28 Jul 2023 15:41:29 +0000 http://www.limilabs.com/blog/?p=1232 Unlock the potential of efficient email processing in .NET with this comprehensive guide on saving email attachments using Mail.dll’s IMAP component and IMAP protocol. In this article, we’ll walk you through the step-by-step process of downloading email messages using Mail.dll’s IMAP component and, more importantly, demonstrate how to effortlessly save all attachments to your disk. […]

The post Save all attachments to disk using IMAP first appeared on Blog | Limilabs.

]]>
Unlock the potential of efficient email processing in .NET with this comprehensive guide on saving email attachments using Mail.dll’s IMAP component and IMAP protocol.

In this article, we’ll walk you through the step-by-step process of downloading email messages using Mail.dll’s IMAP component and, more importantly, demonstrate how to effortlessly save all attachments to your disk.

Email MIME structure

The first thing you need to know is that email attachments are tightly integrated with the email message itself, ensuring that they are conveniently stored and transport together.

In MIME (Multipurpose Internet Mail Extensions), email attachments are stored together with an email message to ensure a structured and standardized way of transmitting and receiving email content with multiple parts.

The primary reason for storing attachments within the email message is to maintain a single cohesive entity that encapsulates all the components of the email, including its text, formatting, and any attached files. By bundling attachments with the message, the entire email becomes a self-contained package, making it easier to handle and process by email clients and servers.

Attachments in Mail.dll

Invoking Imap.GetMessageByUID method is going to download entire email message, including all attachments.

Attachments are stored within the email as part of a mime tree. Usually Quoted-Printable or Base64 encoding is used.

However, with Mail.dll, you don’t need to worry about navigating this mime tree yourself. The library efficiently parses the email’s structure, effortlessly exposing all attachments as familiar .NET collections. This user-friendly approach simplifies the process of handling email attachments, allowing you to focus on building robust and efficient email management solutions with ease.

There are 4 collections that contain attachments:

  • IMail.Attachments – all attachments (includes Visuals, NonVisuals and Alternatives).
  • IMail.Visuals – visual elements, files that should be displayed to the user, such as images embedded in an HTML email.
  • IMail.NonVisuals – non visual elements, “real” attachments.
  • IMail.Alternatives – alternative content representations, for example ical appointment.

How to download all email attachments in .NET

To retrieve all attachments from an email, you can take advantage of the IMail.Attachments collection provided by Mail.dll. This collection serves as a comprehensive repository, housing all the attachments associated with the email.

Each attachment is represented by a dedicated MimeData object, which encapsulates the specific data and metadata of the attachment.

Using the IMail.Attachments collection eliminates the need for manual traversal of the email’s mime tree or deciphering complex structures. Instead, Mail.dll handles the heavy lifting for you, ensuring a streamlined and user-friendly experience when accessing email attachments programmatically.

Installation

The easiest way to install Mail.dll is to download it from nuget via Package Manager:

PM> Install-Package Mail.dll

Alternatively you can download Mail.dll directly from our website.

Download emails and all attachments

The C# code to download all emails and save all attachments using Mail.dll and IMAP is as follows.

using Limilabs.Client.IMAP;
using Limilabs.Mail;
using Limilabs.Mail.MIME
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        using(Imap imap = new Imap())
        {
            imap.ConnectSSL("imap.example.com");
            imap.UseBestLogin("user", "password");

            imap.SelectInbox();
            List<long>; uids = imap.Search(Flag.Unseen);
            foreach (long uid in uids)
            {
                var eml = imap.GetMessageByUID(uid);
                IMail email = new MailBuilder()
                    .CreateFromEml(eml);
                Console.WriteLine(email.Subject);

                foreach (MimeData mime in email.Attachments)
                {
                    mime.Save(@"c:\" + mime.SafeFileName);
                }
            }
            imap.Close();
        }
    }
};

Below is the VB.NET code for your reference:

Imports Limilabs.Client.IMAP
Imports Limilabs.Mail
Imports Limilabs.Mail.MIME
Imports System
Imports System.Collections.Generic

Public Module Module1
    Public Sub Main(ByVal args As String())

        Using imap As New Imap()
            imap.ConnectSSL("imap.example.com")
            imap.UseBestLogin("user", "password")

            imap.SelectInbox()
            Dim uids As List(Of Long) = imap.Search(Flag.Unseen)

            For Each uid As Long In uids
                Dim eml = imap.GetMessageByUID(uid)
                Dim email As IMail = New MailBuilder() _
                    .CreateFromEml(eml)
                Console.WriteLine(email.Subject)

                For Each mime As MimeData In email.Attachments
                    mime.Save("c:\" + mime.SafeFileName)
                Next
            Next
            imap.Close()
        End Using

    End Sub
End Module

Accessing attachment data

You can also save attachment to a specific stream using MimeData.Save(Stream stream).

You can get direct access to attachment binary data with MimeData.GetMemoryStream().

Finally you can get a byte array (byte[]) using MimeData.Data property.

Downloading only parts of the message

IMAP protocol provides very useful features in regard to working with attachments and all are available in Mail.dll .NET IMAP component.

With Mail.dll you can download only parts of email message, which in conjunction with getting basic email information without downloading entire message can make your code extremely fast.

Process emails embedded as attachments

In some situations you’ll receive a message that has another message attached.

You can use Mail.dll to extract all attachments from such inner messages no matter how deep the embedding level is.


Get Mail.dll

The post Save all attachments to disk using IMAP first appeared on Blog | Limilabs.

]]>
https://www.limilabs.com/blog/save-all-attachments-to-disk-using-imap/feed 10
Outlook365: IMAP, POP3, and SMTP settings https://www.limilabs.com/blog/outlook365-imap-pop3-smtp-settings Wed, 02 Jan 2019 14:17:59 +0000 http://www.limilabs.com/blog/?p=3650 Outlook365 supports access via IMAP, POP3 and SMTP protocols. Below you can find the configuration settings for all protocols. Latest Office 365 version For latest Office 365 after the service upgrade, use the following settings: IMAP Server: outlook.office365.comSSL: true-implicit, true-explicit (StartTLS)Port: 993 (default), 143 (default)User: pat@domain.onmicrosoft.com or pat@your-domain.com POP3 Server: outlook.office365.comSSL: true-implicit, true-explicit (StartTLS)Port: 995 […]

The post Outlook365: IMAP, POP3, and SMTP settings first appeared on Blog | Limilabs.

]]>
Outlook365 supports access via IMAP, POP3 and SMTP protocols. Below you can find the configuration settings for all protocols.

Latest Office 365 version

For latest Office 365 after the service upgrade, use the following settings:

IMAP

Server: outlook.office365.com
SSL: true-implicit, true-explicit (StartTLS)
Port: 993 (default), 143 (default)
User: pat@domain.onmicrosoft.com or pat@your-domain.com

POP3

Server: outlook.office365.com
SSL: true-implicit, true-explicit (StartTLS)
Port: 995 (default), 110 (default)
User: pat@domain.onmicrosoft.com or pat@your-domain.com

SMTP

Server: outlook.office365.com
SSL: true-explicit (StartTLS)
Port: 587(default)
User: pat@domain.onmicrosoft.com or pat@your-domain.com

IMAP and POP3 servers allow both: implicit SSL/TLS and explicit SSL/TLS, so you can ConnectSSL method -or- Connect and StartTLS.

SMTP server requires explicit SSL – use Connect and StartTLS method.

Authentication

For Exchange Online/Office 365, we recommend using OAuth 2.0 flows:

Daemons/Services: Password grant (MFA/2FA must be turned off for this account):
https://www.limilabs.com/blog/oauth2-password-grant-office365-exchange-imap-pop3-smtp

Daemons/Services: Client credential flow:
https://www.limilabs.com/blog/oauth2-client-credential-flow-office365-exchange-imap-pop3-smtp

Web apps (requires user interaction):
https://www.limilabs.com/blog/oauth2-web-flow-office365-exchange-imap-pop3-smtp

Standalone devices (requires very little interaction):
https://www.limilabs.com/blog/oauth2-device-flow-office365-exchange-imap-pop3-smtp

Desktop apps (requires user interaction):
https://www.limilabs.com/blog/oauth2-office365-exchange-imap-pop3-smtp

It is no longer possible to re-enable Basic Auth or use App passwords.

// C#

using (Imap client = new Imap())
{
    client.ConnectSSL("outlook.office365.com");
    client.UseBestLogin("user@domain.onmicrosoft.com", "accesstoken");
    ...
}

using (Pop3 client = new Pop3())
{
    client.ConnectSSL("outlook.office365.com");
    client.UseBestLogin("user@domain.onmicrosoft.com", "accesstoken");
    ...
}

using (Smtp client = new Smtp ())
{
    client.Connect("outlook.office365.com");
    client.StartTLS();

    client.UseBestLogin("user@domain.onmicrosoft.com", "accesstoken");
    ...
}
' VB.NET

Using client As New Imap()
	client.ConnectSSL("outlook.office365.com")
	client.UseBestLogin("user@domain.onmicrosoft.com", "accesstoken")
	...
End Using

Using client As New Pop3()
	client.ConnectSSL("outlook.office365.com")
	client.UseBestLogin("user@domain.onmicrosoft.com", "accesstoken")
	...
End Using

Using client As New Smtp()
	client.Connect("outlook.office365.com")
	client.StartTLS()

	client.UseBestLogin("user@domain.onmicrosoft.com", "accesstoken")
	...
End Using

Office 365 pre-upgrade

For latest Office 365 pre-upgrade, use the following settings:

On the main screen go to “Options” / “See All Options…”:

Now click the “Settings for POP, IMAP, and SMTP access…” link:

You can find POP, SMTP and IMAP server addresses and settings on the popup window:

Office365 uses default ports for IMAP, POP3 and SMTP protocols. That means that you don’t need to remember port numbers, as Mail.dll .NET email component is going to use correct port numbers by default.

IMAP

Server: podXXXX.outlook.com
SSL: true-implicit
Port: 993 (default)
User: pat@domain.onmicrosoft.com or pat@your-domain.com

POP3

Server: podXXXX.outlook.com
SSL: true-implicit
Port: 995 (default)
User: pat@domain.onmicrosoft.com or pat@your-domain.com

SMTP

Server: podXXXX.outlook.com
SSL: true-explicit
Port: 587 (default)
User: pat@domain.onmicrosoft.com or pat@your-domain.com

You can find more details about using implicit and explicit SSL or TLS with email protocols:

The post Outlook365: IMAP, POP3, and SMTP settings first appeared on Blog | Limilabs.

]]>
OAuth 2.0 with Gmail over IMAP for installed applications https://www.limilabs.com/blog/oauth2-gmail-imap-installed-applications Mon, 13 Mar 2017 05:01:09 +0000 http://www.limilabs.com/blog/?p=3359 You can also read how to use:   OAuth 2.0 with Gmail over IMAP for web applications (Google.Apis) OAuth 2.0 with Gmail over IMAP for installed applications (Google.Apis) OAuth 2.0 with Gmail over IMAP for service account (Google.Apis) OAuth 2.0 is an open protocol to allow secure API authorization in a simple and standard method […]

The post OAuth 2.0 with Gmail over IMAP for installed applications first appeared on Blog | Limilabs.

]]>
You can also read how to use:

 

OAuth 2.0 is an open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.

This article describes using OAuth 2.0 to access Gmail IMAP and SMTP servers using .NET IMAP component in installed applications scenario. You can also use OAuth 2.0 for web applications.

Google.Apis

Use Nuget to download “Google.Apis.Auth” package.

Import namespaces:

// c#

using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Responses;

using Limilabs.Client.Authentication.Google;

using Limilabs.Client.IMAP;
' VB.NET 

Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Auth.OAuth2.Flows
Imports Google.Apis.Auth.OAuth2.Requests
Imports Google.Apis.Auth.OAuth2.Responses

Imports Limilabs.Client.Authentication.Google

Imports Limilabs.Client.IMAP

Register Application

Before you can use OAuth 2.0, you must register your application using the Google Cloud Console. After you’ve registered copy the “Client ID” and “Client secret” values which you’ll need later.

At least product name must be specified:

Now create credentials:

After you’ve registered, copy the “Client ID” and “Client secret” values, which you’ll need later:

Now we can define clientID, clientSecret and scope variables, as well as Google OAuth 2.0 server addresses. Scope basically specifies what services we want to have access to. In our case it is user’s email address and IMAP/SMTP access:

// C#

string clientID = "XXX.apps.googleusercontent.com";
string clientSecret = "IxBs0g5sdaSDUz4Ea7Ix-Ua";

var clientSecrets = new ClientSecrets
{
    ClientId = clientID,
    ClientSecret = clientSecret
};

var credential = new GoogleAuthorizationCodeFlow(
    new GoogleAuthorizationCodeFlow.Initializer
    {
        ClientSecrets = clientSecrets,
        Scopes = new[] { 
            GoogleScope.ImapAndSmtp.Name, 
            GoogleScope.UserInfoEmailScope.Name}
    });
' VB.NET 

Dim clientID As String = "XXX.apps.googleusercontent.com"
Dim clientSecret As String = "IxBs0g5sdaSDUz4Ea7Ix-Ua"

Dim clientSecrets = New ClientSecrets With { _
	.ClientId = clientID, _
	.ClientSecret = clientSecret _
}

Dim credential = New GoogleAuthorizationCodeFlow( _
    New GoogleAuthorizationCodeFlow.Initializer With { _
    	.ClientSecrets = clientSecrets, _
	    .Scopes = { _
            GoogleScope.ImapAndSmtp.Name,  _
            GoogleScope.UserInfoEmailScope.Name} _
})

Obtain an OAuth 2.0 access token

Now we’ll create authorization url.

As OOB addresses are no longer supported, to receive the authorization code using this URL, your application must be listening on the local web server. This is the recommended mechanism for obtaining the authorization code.

When your app receives the authorization response, for best usability it should respond by displaying an HTML page that instructs the user to close the browser and return to your app.

Your application needs to create a server that listens on this local address:

http://127.0.0.1:port or http://[::1]:port or http://localhost:port

Query your platform for the relevant loopback IP address and start an HTTP listener on a random available port. Substitute port with the actual port number your app listens on.

// C#

AuthorizationCodeRequestUrl url = credential
    .CreateAuthorizationCodeRequest("http://127.0.0.1:1234/auth2callback");

Process.Start(url.Build().ToString());
' VB.NET 

Dim url As AuthorizationCodeRequestUrl = credential _
    .CreateAuthorizationCodeRequest("http://127.0.0.1:1234/auth2callback")

Process.Start(url.Build().ToString())

We are using Process.Start here, but you can also embed WebBrowser control in your application.

At this point user is redirected to Google to authorize the access:

After this step user is redirected to the loopback address you provided.

Your application’s local web server, listening on this address, should obtain code from the url parameter.

Following is a code that reads this code and contacts Google to exchange it for a refresh-token and an access-token:

string authCode = "get from the url";

TokenResponse token = await credential.ExchangeCodeForTokenAsync(
    "", 
    authCode, 
    "http://127.0.0.1/auth2callback", 
    CancellationToken.None);

string accessToken = token.AccessToken;
' VB.NET 

Dim authCode As String = "get from the url";

Dim token As TokenResponse = Await credential.ExchangeCodeForTokenAsync( _
    "",  _
    authCode,  _
    "http://127.0.0.1/auth2callback",  _
    CancellationToken.None)

Dim accessToken As String = token.AccessToken

An access token is usually valid for a maximum of one hour, and allows you to access the user’s data. You also received a refresh token. A refresh token can be used to request a new access token once the previous expired.

Access IMAP/SMTP server

Finally we’ll ask Google for user’s email and use LoginOAUTH2 method to access Gmail’s IMAP server:

// C#

GoogleApi api = new GoogleApi(accessToken);
string user = api.GetEmail();

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap.gmail.com");
    imap.LoginOAUTH2(user, accessToken);

    imap.SelectInbox();
    List<long> uids = imap.Search(Flag.Unseen);

    foreach (long uid in uids)
    {
        var eml = imap.GetMessageByUID(uid);
        IMail email = new MailBuilder().CreateFromEml(eml);
        Console.WriteLine(email.Subject);
    }
    imap.Close();
}
' VB.NET 

Dim api As New GoogleApi(accessToken)
Dim user As String = api.GetEmail()

Using imap As New Imap()
	imap.ConnectSSL("imap.gmail.com")
	imap.LoginOAUTH2(user, accessToken)

	imap.SelectInbox()
	Dim uids As List(Of Long) = imap.Search(Flag.Unseen)

	For Each uid As Long In uids
		Dim eml = imap.GetMessageByUID(uid)
		Dim email As IMail = New MailBuilder().CreateFromEml(eml)
		Console.WriteLine(email.Subject)
	Next
	imap.Close()
End Using

Refreshing access token

An access token is usually short lived and valid for a maximum of one hour. The main reason behind this is security and prevention of replay attacks. This means that for long-lived applications you need to refresh the access token.

Your refresh token will be sent only once – don’t loose it!

We recommend storing entire TokenResponse object received from GoogleAuthorizationCodeFlow.ExchangeCodeForTokenAsync method call. This object contains both: refresh token and access token, along with its expiration time.

The process of refreshing access token is simple:

// c#

TokenResponse refreshed = await credential.RefreshTokenAsync(
    "", 
    token.RefreshToken, 
    CancellationToken.None);
' VB.NET 

Dim refreshed As TokenResponse = Await credential.RefreshTokenAsync( _
    "",  _
    token.RefreshToken,  _
    CancellationToken.None)

The post OAuth 2.0 with Gmail over IMAP for installed applications first appeared on Blog | Limilabs.

]]>
OAuth 2.0 with Gmail over IMAP for web applications https://www.limilabs.com/blog/oauth2-gmail-imap-web-applications Mon, 13 Mar 2017 05:00:39 +0000 http://www.limilabs.com/blog/?p=3328 You can also read how to use:   OAuth 2.0 with Gmail over IMAP for web applications (Google.Apis) OAuth 2.0 with Gmail over IMAP for installed applications (Google.Apis) OAuth 2.0 with Gmail over IMAP for service account (Google.Apis) OAuth 2.0 is an open protocol to allow secure API authorization in a simple and standard method […]

The post OAuth 2.0 with Gmail over IMAP for web applications first appeared on Blog | Limilabs.

]]>
You can also read how to use:

 

OAuth 2.0 is an open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.

This article describes using OAuth 2.0 to access Gmail IMAP and SMTP servers using .NET IMAP component in web application scenario (ASP.NET/ASP.NET MVC). You can also use OAuth 2.0 for installed applications.

Google.Apis

Use Nuget to download “Google.Apis.Auth” package.

Import namespaces:

// c#

using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Responses;

using Limilabs.Client.Authentication.Google;

using Limilabs.Client.IMAP;
' VB.NET 

Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Auth.OAuth2.Flows
Imports Google.Apis.Auth.OAuth2.Requests
Imports Google.Apis.Auth.OAuth2.Responses

Imports Limilabs.Client.Authentication.Google

Imports Limilabs.Client.IMAP

Register Application

Before you can use OAuth 2.0, you must register your application using the Google Cloud Console. After you’ve registered, specify “Redirect URI” and copy the “Client ID” and “Client secret” values which you’ll need later.

At least product name must be specified:

Now create credentials:

Specify redirect URI:

After you’ve registered, copy the “Client ID” and “Client secret” values, which you’ll need later:

Now we can define clientID, clientSecret, redirect url and scope variables, as well as Google OAuth 2.0 server addresses. Scope basically specifies what services we want to have access to. In our case it is user’s email address and IMAP/SMTP access:

// C#

string clientID = "XXX.apps.googleusercontent.com";
string clientSecret = "IxBs0g5sdaSDUz4Ea7Ix-Ua";
string redirectUri = "https://www.example.com/oauth2callback";

var clientSecrets = new ClientSecrets
{
    ClientId = clientID,
    ClientSecret = clientSecret
};

var credential = new GoogleAuthorizationCodeFlow(
    new GoogleAuthorizationCodeFlow.Initializer
        {
            ClientSecrets = clientSecrets,
            Scopes = new[] { 
                GoogleScope.ImapAndSmtp.Name, 
                GoogleScope.UserInfoEmailScope.Name}
        });
' VB.NET 

Dim clientID As String = "XXX.apps.googleusercontent.com"
Dim clientSecret As String = "IxBs0g5sdaSDUz4Ea7Ix-Ua"
Dim redirectUri As String = "https://www.example.com/oauth2callback"

Dim clientSecrets = New ClientSecrets With { _
	.ClientId = clientID, _
	.ClientSecret = clientSecret _
}

Dim credential = New GoogleAuthorizationCodeFlow(New GoogleAuthorizationCodeFlow.Initializer With { _
	.ClientSecrets = clientSecrets, _
	.Scopes = {GoogleScope.ImapAndSmtp.Name, GoogleScope.UserInfoEmailScope.Name} _
})

Obtain an OAuth 2.0 access token

Now we’ll create authorization url:

// C#

AuthorizationCodeRequestUrl url = credential
    .CreateAuthorizationCodeRequest(redirectUri);
' VB.NET 

Dim url As AuthorizationCodeRequestUrl = credential _
    .CreateAuthorizationCodeRequest(redirectUri)

Now we need to redirect the client:

// c#

return new RedirectResult(url.Build().ToString());
' VB.NET 

Return New RedirectResult(url.Build().ToString())

At this point user is redirected to Google to authorize the access:

After this step user is redirected back to your website (https://www.example.com/oauth2callback), with code request parameter:
https://www.example.com/oauth2callback?code=4/5Y7M4cARD9hrt0nuKnQa0YgasdbwprRtIIjk4Fus#

// C#

public class OAauth2CallbackController : Controller
{
    public ActionResult Index(string code)
    {
        ...
    }
}
' VB.NET 

Public Class OAauth2CallbackController
    Inherits Controller
    Public Function Index(code As String) As ActionResult
        ...
    End Function
End Class

Following is this callback code. Its purpose is to get a refresh-token and an access-token:

// c#

string authCode = code;

TokenResponse token = await credential.ExchangeCodeForTokenAsync(
    "", 
    authCode, 
    redirectUri, 
    CancellationToken.None);

string accessToken = token.AccessToken;
' VB.NET 

Dim authCode As String = code

Dim token As TokenResponse = Await credential.ExchangeCodeForTokenAsync( _
    "",  _
    authCode,  _
    redirectUri,  _
    CancellationToken.None)

Dim accessToken As String = token.AccessToken

An access token is usually valid for a maximum of one hour, and allows you to access the user’s data. You also received a refresh token. A refresh token can be used to request a new access token once the previous expired.

Access IMAP/SMTP server

Finally we’ll ask Google for user’s email and use LoginOAUTH2 method to access Gmail’s IMAP server:

// c#

GoogleApi api = new GoogleApi(accessToken);
string user = api.GetEmail();

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap.gmail.com");
    imap.LoginOAUTH2(user, accessToken);

    imap.SelectInbox();
    List<long> uids = imap.Search(Flag.Unseen);

    foreach (long uid in uids)
    {
        var eml = imap.GetMessageByUID(uid);
        IMail email = new MailBuilder().CreateFromEml(eml);
        Console.WriteLine(email.Subject);
    }
    imap.Close();
}
' VB.NET 

Dim api As New GoogleApi(accessToken)
Dim user As String = api.GetEmail()

Using imap As New Imap()
	imap.ConnectSSL("imap.gmail.com")
	imap.LoginOAUTH2(user, accessToken)

	imap.SelectInbox()
	Dim uids As List(Of Long) = imap.Search(Flag.Unseen)

	For Each uid As Long In uids
		Dim eml = imap.GetMessageByUID(uid)
		Dim email As IMail = New MailBuilder().CreateFromEml(eml)
		Console.WriteLine(email.Subject)
	Next
	imap.Close()
End Using

Refreshing access token

An access token is usually short lived and valid for a maximum of one hour. The main reason behind this is security and prevention of replay attacks. This means that for long-lived applications you need to refresh the access token.

Your refresh token will be sent only once – don’t loose it!

We recommend storing entire TokenResponse object received from GoogleAuthorizationCodeFlow.ExchangeCodeForTokenAsync method call. This object contains both: refresh token and access token, along with its expiration time.

The process of refreshing access token is simple:

// c#

TokenResponse refreshed = await credential.RefreshTokenAsync(
    "", 
    token.RefreshToken, 
    CancellationToken.None);
' VB.NET 

Dim refreshed As TokenResponse = Await credential.RefreshTokenAsync( _
    "",  _
    token.RefreshToken,  _
    CancellationToken.None)

The post OAuth 2.0 with Gmail over IMAP for web applications first appeared on Blog | Limilabs.

]]>
Logging in Mail.dll email client https://www.limilabs.com/blog/logging-in-mail-dll Mon, 01 Aug 2016 16:03:54 +0000 http://www.limilabs.com/blog/?p=1478 This article provides a comprehensive guide on how to perform logging within the Mail.dll .NET email client. It outlines step-by-step instructions for implementing robust logging mechanisms, enhancing troubleshooting capabilities, and tracking email communication effectively. By following the methods detailed in the article, VisualBasic and C# developers can seamlessly integrate logging features into their applications, gaining […]

The post Logging in Mail.dll email client first appeared on Blog | Limilabs.

]]>
This article provides a comprehensive guide on how to perform logging within the Mail.dll .NET email client. It outlines step-by-step instructions for implementing robust logging mechanisms, enhancing troubleshooting capabilities, and tracking email communication effectively.

By following the methods detailed in the article, VisualBasic and C# developers can seamlessly integrate logging features into their applications, gaining valuable insights into the Imap, Pop3 and Smtp clients behavior and facilitating streamlined debugging processes.

To enable logging for all Mail.dll .NET clients (Imap, Pop3, Smtp) you only need to add the following line before you connect:

// C# version:

Limilabs.Mail.Log.Enabled = true;
' VB.NET version:

Limilabs.Mail.Log.Enabled = True

You can observe the log output by:

  • looking at the Visual Studio’s output window (View/Output/’Show output from’: Debug)
  • subscribing to Log.WriteLine event
  • defining custom listeners using your application’s config file (App.config or Web.config)
  • using log4net

This is how the log looks like in the Visual Studio’s output window:

For regular .NET framework you can also enable logging using your application’s config file (App.config, Web.config):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.diagnostics>

      <switches>
        <add name="Mail.dll" value="Verbose" />
      </switches>

    </system.diagnostics>
</configuration>

Logging with log4net

If you are using log4net, Mail.dll is going to use log4net instead of standard .NET System.Net.TraceSource class. Please refer to log4net manual on how to capture log entries.

Mail.dll uses logger called “Mail.dll”

_logger = LogManager.GetLogger("Mail.dll")

and level Info _logger.Info(message) to log information.

Please remember that even when using log4net, you need to enable logging by setting “Limilabs.Mail.Log.Enabled = True” or by setting Mail.dll trace switch in the config file (App.config, Web.config) to Verbose as shown above.

Log.WriteLine

Limilabs.Mail.Log class exposes WriteLine event. You can use that event to subscribe your own logging library in both .NET and .NET framework.

// C#

Limilabs.Mail.Log.WriteLine += Console.WriteLine;
' VB.NET

AddHandler Limilabs.Mail.Log.WriteLine, AddressOf Console.WriteLine

Log to file (.NET framework)

You’ll need to define a TextWriterTraceListener that writes to a file and connect it with Mail.dll trace source. The easiest solution is to modify your application’s config file App.config or Web.config accordingly:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.diagnostics>

        <trace autoflush="true"/>

        <switches>
            <add name="Mail.dll" value="Verbose"/>
        </switches>

        <sources>
            <source name="Mail.dll">
                <listeners>
                    <add name="MailLogFile"/>
                </listeners>
            </source>
        </sources>

        <sharedListeners>
            <add
                name="MailLogFile"
                type="System.Diagnostics.TextWriterTraceListener"
                initializeData="c:\folder-with-write-access\mail.log"/>
        </sharedListeners>

    </system.diagnostics>
</configuration>

The post Logging in Mail.dll email client first appeared on Blog | Limilabs.

]]>
Delete email permanently in Gmail https://www.limilabs.com/blog/delete-email-permanently-in-gmail https://www.limilabs.com/blog/delete-email-permanently-in-gmail#comments Fri, 04 Sep 2015 10:00:37 +0000 http://www.limilabs.com/blog/?p=575 If you delete a message from your Inbox or one of your custom folders, it will still appear in [Gmail]/All Mail. Here’s why: in most folders, deleting a message simply removes that folder’s label from the message, including the label identifying the message as being in your Inbox. [Gmail]/All Mail shows all of your messages, […]

The post Delete email permanently in Gmail first appeared on Blog | Limilabs.

]]>

If you delete a message from your Inbox or one of your custom folders, it will still appear in [Gmail]/All Mail.

Here’s why: in most folders, deleting a message simply removes that folder’s label from the message, including the label identifying the message as being in your Inbox.

[Gmail]/All Mail shows all of your messages, whether or not they have labels attached to them.

If you want to permanently delete a message from all folders:

  1. Move it to the [Gmail]/Trash folder (or [Gmail]/Bin or national version).
  2. Delete it from the [Gmail]/Trash folder (or [Gmail]/Bin or national version).

All emails in [Gmail]/Spam and [Gmail]/Trash are deleted after 30 days.
If you delete a message from [Gmail]/Spam or [Gmail]/Trash, it will be deleted permanently.

Here’s how this looks like using Mail.dll .NET IMAP component:

Delete emails permanently (C# version)

// C# version:

using(Imap imap = new Imap())
{
	imap.ConnectSSL("imap.gmail.com");
	imap.UseBestLogin("user@gmail.com", "password");

	// Recognize Trash folder
	List<FolderInfo> folders = imap.GetFolders();
 	CommonFolders common = new CommonFolders(folders);
 	FolderInfo trash = common.Trash;

	// Find all emails we want to delete
	imap.SelectInbox();
	List<long> uids = imap.Search(
		Expression.Subject("email to delete"));

	// Move email to Trash
	List<long> uidsInTrash = new List<long>();
	foreach (long uid in uids)
	{
		long uidInTrash = (long)imap.MoveByUID(uid, trash);
		uidsInTrash.Add(uidInTrash);
	}

	// Delete moved emails from Trash
	imap.Select(trash);
	foreach (long uid in uidsInTrash)
	{
		imap.DeleteMessageByUID(uid);
	}

	imap.Close();
}

Delete emails permanently (VB.NET version)

Using imap As New Imap()
	imap.ConnectSSL("imap.gmail.com")
	imap.UseBestLogin("user@gmail.com", "password")

	' Recognize Trash folder
	Dim folders As List(Of FolderInfo) = imap.GetFolders()
	Dim common As CommonFolders = new CommonFolders(folders)
	Dim trash As FolderInfo = common.Trash

	' Find all emails we want to delete
	imap.SelectInbox()
	Dim uids As List(Of Long) = imap.Search( _
		Expression.Subject("email to delete"))

	' Move email to Trash
	Dim uidsInTrash As New List(Of Long)
	For Each uid As Long In uids
		Dim uidInTrash As Long = imap.MoveByUID(uid,trash)
		uidsInTrash.Add(uidInTrash)
	Next

	' Delete moved emails from Trash
	imap.[Select](trash)
	For Each uid As Long In uidsInTrash
		imap.DeleteMessageByUID(uid)
	Next

	imap.Close()
End Using

You can also use bulk methods to handle large amount of emails faster:

Delete emails permanently in bulk (C# version)

using(Imap imap = new Imap())
{
	imap.ConnectSSL("imap.gmail.com");
	imap.UseBestLogin("user@gmail.com", "password");

	// Recognize Trash folder
	List<FolderInfo> folders = imap.GetFolders();
 	CommonFolders common = new CommonFolders(folders);
 	FolderInfo trash = common.Trash;

	// Find all emails we want to delete
	imap.SelectInbox();
	List<long> uids = imap.Search(
		Expression.Subject("email to delete"));

	// Move emails to Trash
	List<long> uidsInTrash = imap.MoveByUID(uids, trash);

	// Delete moved emails from Trash
	imap.Select(trash);
	imap.DeleteMessageByUID(uidsInTrash);

	imap.Close();
}

Delete emails permanently in bulk (VB.NET version)

Using imap As New Imap()
	imap.ConnectSSL("imap.gmail.com")
	imap.UseBestLogin("user@gmail.com", "password")

	' Recognize Trash folder
	Dim folders As List(Of FolderInfo) = imap.GetFolders()
	Dim common As CommonFolders = new CommonFolders(folders)
	Dim trash As FolderInfo = common.Trash

	' Find all emails we want to delete
	imap.SelectInbox()
	Dim uids As List(Of Long) = imap.Search( _
		Expression.Subject("email to delete"))

	' Move email to Trash
	Dim uidsInTrash As List(Of Long) = imap.MoveByUID(uids, trash)

	' Delete moved emails from Trash
	imap.[Select](trash)
	imap.DeleteMessageByUID(uidsInTrash)

	imap.Close()
End Using

Please also note that there are 2 additional sections in the “Gmail settings”/”Forwarding and POP/IMAP” tab:

“When I mark a message in IMAP as deleted:”

  • Auto-Expunge on – Immediately update the server. (default)
  • Expunge off – Wait for the client to update the server.

“When a message is marked as deleted and expunged from the last visible IMAP folder:”

  • Archive the message (default)
  • Move the message to the Trash
  • Immediately delete the message forever

Those settings change the default behavior of the account and modify DeleteMessage* methods behavior.

The post Delete email permanently in Gmail first appeared on Blog | Limilabs.

]]>
https://www.limilabs.com/blog/delete-email-permanently-in-gmail/feed 18
Using Limilabs’ Ftp.dll with zOS Mainframes https://www.limilabs.com/blog/using-limilabs-ftp-dll-with-zos-mainframes Wed, 17 Dec 2014 09:47:42 +0000 http://www.limilabs.com/blog/?p=4828 I purchased the Limilabs FTP product for FTP because I needed to send data to and from an IBM mainframe from my VB.NET program running in Windows. In particular I needed to be able to submit jobs, and receive the job output. These notes show how it’s done. Introduction FTP to/from IBM computers is pretty […]

The post Using Limilabs’ Ftp.dll with zOS Mainframes first appeared on Blog | Limilabs.

]]>
I purchased the Limilabs FTP product for FTP because I needed to send data to and from an IBM mainframe from my VB.NET program running in Windows. In particular I needed to be able to submit jobs, and receive the job output. These notes show how it’s done.

Introduction

FTP to/from IBM computers is pretty much like any other FTP except for two things.
1. IBM Mainframe and Midrange computers mostly use EBCDIC encoding rather than ASCII. With the FTP defaults your data can be garbled and useless when it arrives at the other end.
2. The SITE command is used to submit jobs to the mainframe, and get the results back.

Getting Started

I created a class called “JazzFTP” to wrap the Limilabs’ code. This was going to contain the functions that I wanted for my project, and so I started by defining the common elements that all methods would use. In my situation every FTP would be authenticated, and would be exchanging text data (not binary) with the remote computer.

Here is the initial class definition:

Imports Limilabs.FTP.Client

Public Class JazzFTP
    '   This class wraps the FTP library from Limilabs (/ftp)
    '   All methods
    '   1   Connect and logon using information from MySettings:  Sub LoginFTP
    '   2   Perform their action based on their parameters
    '   3   Close the connection
    Dim ftp As New Ftp()
    Dim response As FtpResponse
    Private Sub LoginFTP()
        ftp.Connect(My.Settings.SubmitIP)
        ftp.Login(My.Settings.Userid, My.Settings.Password)
    End Sub
    '   My functions will be written here
End Class

Basic FTP

Here is my first method, a basic function to upload a text file: –

    Function Upload(DestinationFile As String, Uploadfile As String) As String 
        LoginFTP()
        ftp.TransfersDataType = FtpDataType.Ascii
        response = ftp.Upload(DestinationFile, Uploadfile)
        ftp.Close()
        Return response.message
    End Function

FTP’s default is Binary, which is correct if you are transmitting a .JPG or other binary object, and it probably doesn’t matter if you are transmitting text to/from another Windows computer or a Unix computer. However if you are transmitting to/from an IBM mainframe or midrange computer it probably needs EBCDIC rather than ASCII characters. You must tell it that the file is Ascii text, not binary, otherwise it won’t be converted and it will be gibberish when you examine it on the mainframe.

Although this code above works, it is very fragile: the FTP server has to be up and running, you have to get the connection details exactly right, the source and destination files must exist, and so on. Since I couldn’t guarantee all of these details, I enclosed the code in Try/Catch to deal with any errors. For the time being I’ve simply used MsgBox to display the error message.

    Function Upload(DestinationFile As String, Uploadfile As String) As String
        Try
            LoginFTP()
            ftp.TransfersDataType = FtpDataType.Ascii
            response = ftp.Upload(DestinationFile, Uploadfile)
            ftp.Close()
            Return response.EndLine
        Catch ex As Exception
            MsgBox(ex.Message)
            Return ex.Message
        End Try
    End Function

Download, which is not illustrated, is similar except that you’d use ftp.Download. Again, you specify:

            ftp.TransfersDataType = FtpDataType.Ascii

Submitting Jobs and Receiving Job Output

Submitting a job is essentially an upload with a twist. Instead of uploading the file containing the job to a named file on the mainframe, you upload it to the JES (Job Entry System) input queue. Here is the basic code:

            response = ftp.Site("FILETYPE=JES")
            ftp.TransfersDataType = FtpDataType.Ascii
            response = ftp.Upload("JES", JCLFile)

The first line uses “ftp.Site”. Site means that this is a site-specific command, something that the FTP system at the other end will presumably know about. For an IBM mainframe “FILETYPE=JES” means that the data is going to and from JES.

The third line uploads the file in which we have prepared our job: in this case JCLFile is a file containing something like this: –

//IBMUSERH JOB  ,CLASS=A,MSGCLASS=H,NOTIFY=&SYSUID,COND=(8,LT) 
//*** COPY SOURCE INTO SOURCE LIBRARY
//COPY EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=*
//SYSIN DD DUMMY
//SYSUT2 DD DSN=IBMUSER.MANAJAZZ.SRCLIB(CRDTA1),DISP=SHR
//SYSUT1 DD *

Like any upload the FTP client syntax requires a destination file name, but because of the preceding FILETYPE=JES this will be ignored. I have written “JES” purely for documentation.

This will submit the job and it will run, appearing in the output like this:

tasks

Of course we can view the job output on the mainframe, but we may want to return it to Windows. We do this by downloading the file by naming the JobID – JOB00594 in this case – and again using the Site command. The essential code is: –

        response = ftp.Site("FILETYPE=JES")
        ftp.TransfersDataType = FtpDataType.Ascii
        ftp.Download(Jobname, LocalPath)

But how do we get the Jobname? JES returns a message with this information when the job is submitted. We need to add code to the Job Submission logic to extract this from the message. In function JobSub

       response = ftp.Upload("JES", JCLFile)

upload the job and (if all goes well) returns a message like
“It is known to JES as JOB00594″
This code extracts JOB00594” and puts it into variable JobName

       Dim TestString As String = "It is known to JES as"
       If Mid(response.Message, 1, Len(TestString)) = TestString Then  'Should be true
           Jobname = Trim(Mid(response.Message, Len(TestString) + 1))
       End If

Now, since it is logical that if we submit a job we’ll want to get it back, I coded this in the JobSub function: –

    Function JobSub(JCLFile As String, ByRef Jobname As String) As FtpResponse
        '   JCLFile is path to a .JCL file (format .txt) containing the job to be submitted
        '   If successful submission, the job name is returned in JobName
        Dim Tstring As String = ""
        Try
            Jobname = "Unknown"
            LoginFTP()
            response = ftp.Site("FILETYPE=JES")
            ftp.TransfersDataType = FtpDataType.Ascii
            response = ftp.Upload("JES", JCLFile)
            Dim TestString As String = "It is known to JES as"
            If Mid(response.Message, 1, Len(TestString)) = TestString Then  'Should be true
                Jobname = Trim(Mid(response.Message, Len(TestString) + 1))
            End If
            JobGet(Jobname, False)
            ftp.Close()
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Jazz FTP")
            Return response
        End Try
        Return response
    End Function

and I coded JobGet to accept these parameters: –

    Function JobGet(Jobname As String, Optional Login As Boolean = True) As FtpResponse
        '   Get job output, save as Jobname.txt in Jazz Program Library.  
        If Login Then
            LoginFTP()
        End If
        response = ftp.Site("FILETYPE=JES")
        ftp.TransfersDataType = FtpDataType.Ascii
        Dim LocalPath As String = My.Settings.UserCommonPath & "\" & My.Settings.Programs & "\" & Jobname & ".txt"
        Jazzworkbench.ShowBtnResults(Jobname, Jazzworkbench.ResultsStatus.Pending)
        ftp.Download(Jobname, LocalPath)
        ftp.DeleteFile(Jobname)
        Jazzworkbench.ShowBtnResults(Jobname, Jazzworkbench.ResultsStatus.JobReturned)
        ftp.Close()
        Return response
    End Function

Once the job output has been downloaded I didn’t want to leave it cluttering up my Held Job Output Queue, so after the Download

        ftp.DeleteFile(Jobname)

gets rid of it.

This all works for my test jobs (which are very quick) and provided that mainframe FTP server is available.

If you want to know any more about my project to revolutionize mainframe programming, then have a look at www.jazzsoftware.co.nz

Best wishes with your programming,
Robert Barnes.

The post Using Limilabs’ Ftp.dll with zOS Mainframes first appeared on Blog | Limilabs.

]]>
OAuth 2.0 with Gmail over IMAP for service account https://www.limilabs.com/blog/oauth2-gmail-imap-service-account Thu, 11 Sep 2014 09:36:51 +0000 http://www.limilabs.com/blog/?p=3904 You can also read how to use:   OAuth 2.0 with Gmail over IMAP for web applications (Google.Apis) OAuth 2.0 with Gmail over IMAP for installed applications (Google.Apis) OAuth 2.0 with Gmail over IMAP for service account (Google.Apis) In this article I’ll show how to access Gmail account of any domain user, using OAuth 2.0, […]

The post OAuth 2.0 with Gmail over IMAP for service account first appeared on Blog | Limilabs.

]]>
You can also read how to use:

 

In this article I’ll show how to access Gmail account of any domain user, using OAuth 2.0, .NET IMAP component and service accounts. The basic idea is that domain administrator can use this method to access user email without knowing user’s password.

This scenario is very similar to 2-legged OAuth, which uses OAuth 1.0a. Although it still works, it has been deprecated by Google and OAuth 2.0 service accounts were introduced.

The following describes how to use XOAUTH2 and OAuth 2.0 to achieve the equivalent of 2-legged OAuth.

Google.Apis

Use Nuget to download “Google.Apis.Auth” package.

Import namespaces:

// c#

using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Responses;

using System.Security.Cryptography.X509Certificates;

using Limilabs.Client.Authentication.Google;

using Limilabs.Client.IMAP;
' VB.NET 

Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Auth.OAuth2.Flows
Imports Google.Apis.Auth.OAuth2.Requests
Imports Google.Apis.Auth.OAuth2.Responses

Imports System.Security.Cryptography.X509Certificates

Imports Limilabs.Client.Authentication.Google

Imports Limilabs.Client.IMAP

Google Cloud

First you need to visit Google Cloud Console and create a project:

Now create a new service account:

Add a service name and remember an email address assigned to your service:

Then you need to create a private key for this service:

Download and save this private key (XYZ.p12), you’ll need that later:

Google Domain administration

Final part is to allow this service to access your domain. You’ll perform this steps in your domain administration panel.

Remember the Client ID first, and go to your domain administration panel:

In the main menu select Security / Access and data control / API controls

Then Manage domain wide delegation

Use previously remembered Client ID and https://mail.google.com/, which is IMAP/SMTP API scope:

Alternatively you can use https://www.googleapis.com/auth/gmail.imap_admin scope.

When authorized with this scope, IMAP connections behave differently:

  • All labels are shown via IMAP, even if users disabled “Show in IMAP” for the label in the Gmail settings.
  • All messages are shown via IMAP, regardless of what the user set in “Folder Size Limits” in the Gmail settings.

Access IMAP/SMTP server

// C#

const string serviceAccountEmail = "name@xxxxxxxxxx.gserviceaccount.com";
const string serviceAccountCertPath = @"c:\XYZ.p12";
const string serviceAccountCertPassword = "notasecret";
const string userEmail = "user@your-domain.com";

X509Certificate2 certificate = new X509Certificate2(
    serviceAccountCertPath,
    serviceAccountCertPassword,
    X509KeyStorageFlags.Exportable);

ServiceAccountCredential credential = new ServiceAccountCredential(
    new ServiceAccountCredential.Initializer(serviceAccountEmail)
    {
        Scopes = new[] { "https://mail.google.com/" },
        // Scopes = new[] { "https://www.googleapis.com/auth/gmail.imap_admin" },

        User = userEmail
    }.FromCertificate(certificate));

bool success = await credential.RequestAccessTokenAsync(
    CancellationToken.None);

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap.gmail.com");
    imap.LoginOAUTH2(userEmail, credential.Token.AccessToken);

    imap.SelectInbox();

    foreach (long uid in uids)
    {
        var eml = client.GetMessageByUID(uid);
        IMail email = new MailBuilder().CreateFromEml(eml);
        Console.WriteLine(email.Subject);
    }

    imap.Close();
}
' VB.NET

Const serviceAccountEmail As String = "name@xxxxxxxxxx.gserviceaccount.com"
Const serviceAccountCertPath As String = "c:\XYZ.p12"
Const serviceAccountCertPassword As String = "notasecret"
Const userEmail As String = "user@your-domain.com"

Dim certificate As New X509Certificate2(serviceAccountCertPath, serviceAccountCertPassword, X509KeyStorageFlags.Exportable)

Dim credential As New ServiceAccountCredential(New ServiceAccountCredential.Initializer(serviceAccountEmail) With { _
	.Scopes = {"https://mail.google.com/"}, _
	' .Scopes = {"https://www.googleapis.com/auth/gmail.imap_admin"}, _
	.User = userEmail _
}.FromCertificate(certificate))

Dim success As Boolean = credential.RequestAccessTokenAsync(
    CancellationToken.None).Result

Using imap As New Imap()
	imap.ConnectSSL("imap.gmail.com")
	imap.LoginOAUTH2(userEmail, credential.Token.AccessToken)

	imap.SelectInbox()

	For Each uid As Long In uids
		Dim eml = client.GetMessageByUID(uid)
		Dim email As IMail = New MailBuilder().CreateFromEml(eml)
		Console.WriteLine(email.Subject)
	Next

	imap.Close()
End Using

The post OAuth 2.0 with Gmail over IMAP for service account first appeared on Blog | Limilabs.

]]>